home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_0_m.arj / ALIAS1.ASM < prev    next >
Assembly Source File  |  1990-01-04  |  82KB  |  2,621 lines

  1.         page    66,132
  2. ;============================================================================
  3. ; ALIAS.COM adds a command line stack, a command line editor, and
  4. ; an alias function to COMMAND.COM.  Syntax is:
  5. ;
  6. ;    ALIAS [alias [command]] [/F filename] [/S nn] [/U]
  7. ;             [/B] [/E] [/D] [/L] [/U] [/*] [//]
  8. ;
  9. ; where /B = Set size of buffer for future alias commands
  10. ;       /D = Disable alias translation
  11. ;       /E = Enable alias translation
  12. ;       /F = Filename of file with list of commands
  13. ;       /L = List aliases currently in list
  14. ;       /M = Set minimum command length to save
  15. ;       /S = Size of command line stack where "nn" is the number of commands
  16. ;            to save
  17. ;       /U = Uninstall the program
  18. ;       /* or // = Comment. Ignore remainder of the line.
  19. ;
  20. ;
  21. ; Revision History:
  22. ;
  23. ;     Version 1.0    Initial Release        PC Magazine Vol 8 Num 22
  24. ;
  25. ;     Version 1.1    Fixed %% bug        January 3, 1989
  26. ;                       Fixed DOS 3.2 bug
  27. ;                       Now works in OS/2 DOS box
  28. ;                       Support for COMMAND.COM shelling
  29. ;                       Reduced installation memory requirments
  30. ;
  31. ;============================================================================
  32.  
  33.         code    segment
  34.         assume    cs:code
  35.  
  36.         org    2ch
  37. env_segment    dw    ?            ;Word containing the segment
  38.                         ;  of the program's env. block.
  39.         org    80h
  40. command_tail    db    ?            ;Offset of the command tail.
  41.  
  42.         org    100h
  43.  
  44. main:        jmp    initialize
  45. program        db    13,10,"ALIAS 1.1 "
  46. copyright    db    "(c) 1990 Ziff Communications Co.",10,13
  47. authors        db    "PC Magazine ",254," Doug Boling and Jeff Prosise"
  48.         db    10,13,"$",1Ah
  49. ;
  50. ;Change the following two numbers to adjust the size of alias on installation.
  51. ;
  52. filebuf_size    dw    0400h            ;Size of input file buffer.
  53. max_code_size    dw    0AF0h            ;Max size of installed code.
  54.  
  55. aliaslist_ptr    dd    ?                     ;Pointer to alias list.
  56. aliaslist_size    dw    ?                 ;Pointer to end of list seg
  57. work_buff_ptr    dw    ?            ;Pointer to alias working buff
  58.  
  59. chk_alias    db    1            ;Alias enable flag.
  60. minlength    db    1            ;Minimum len of cmd to stack
  61. cmdstack_base    dw    ?            ;Offset of command stack
  62. cmdstack_size    dw    16            ;Size of command stack.
  63.  
  64. cmdcom_psp    dw    0            ;Segment of COMMAND.COM PSP
  65. master_env    dw    0            ;Segment of master environment
  66.  
  67. cef_pointer    dd    ?            ;Pointer to critical err flag
  68. dos_version    dw    0            ;DOS Version number
  69.  
  70. mystack_ptr    dw    offset end_of_resident + 512 ;Ptr to internal stack
  71. saved_ss    dw    ?
  72. saved_sp    dw    ?
  73. int21h        dd    -1            ;Int 21 vector (DOS)
  74. int2fh        dd    -1            ;Int 2f vector (DOS MULTIPLEX)
  75.  
  76. multiplex_id    db    0dbh            ;Program ID for multiplex int
  77.  
  78. points        dw    ?            ;Scan lines per character
  79. columns        db    ?            ;Number of screen columns
  80. cursor_mode    dw    ?            ;Cursor mode
  81. bufferptr    db    ?            ;Input buffer pointer
  82. next_ptr    dw    0            ;Address where next command
  83.                         ;  will be stored
  84. cmd_ptr        dw    0            ;Address of current command
  85.                         ;  in command stack
  86. insert_flag    db    0            ;0 = insert off, 1 = on
  87. exkeys        db    71,72,75,77,79,80    ;Extended keycode list
  88.         db    82,83,115,116,117
  89. exkeys_end    =    $
  90.  
  91. ex_entry    dw    offset ctrl_end        ;Jump table for extended
  92.         dw    offset ctrl_right    ;  keycodes
  93.         dw    offset ctrl_left
  94.         dw    offset delete
  95.         dw    offset toggle_ins
  96.         dw    offset next_cmd
  97.         dw    offset eol
  98.         dw    offset move_right
  99.         dw    offset move_left
  100.         dw    offset prev_cmd
  101.         dw    offset home
  102.  
  103. ;============================================================================
  104. ; DOSINT processes calls to interrupt 21h
  105. ;============================================================================
  106. dosint        proc    far
  107.         assume    cs:code,ds:nothing,es:nothing
  108.          cmp    ah,0ah            ;Check for char input
  109.          je    dosint_1            ;If so, continue
  110. goto_dos:
  111.         jmp    cs:[int21h]             ;else pass the call to DOS
  112. ;
  113. ;Compare the active PSP with COMMAND.COM PSP.
  114. ;
  115. dosint_1:
  116.         push    ax            ;Save registers
  117.         push    bx
  118.         mov    ah,51h            ;Get active PSP segment
  119.         cmp    word ptr cs:[dos_version],310h
  120.         jb    early_dos
  121.         pushf
  122.         call    cs:[int21h]
  123.         jmp    short chkpsp1
  124. early_dos:
  125.         push    es            ;If before DOS 3.1, set
  126.         les    bx,cs:[cef_pointer]    ;  critical error flag to
  127.         inc    byte ptr es:[bx]    ;  force DOS to use the aux
  128.         pushf                           ;  stack.
  129.         call    cs:[int21h]        ;Get active PSP segment
  130.         mov    ax,bx
  131.         les    bx,cs:[cef_pointer]    ;Reset critical error flag
  132.         dec    byte ptr es:[bx]
  133.         mov    bx,ax
  134.         pop    es
  135. chkpsp1:
  136.         cmp    bx,cs:[cmdcom_psp]    ;See if COMMAND.COM active.
  137.         je    dosint_2
  138.  
  139.         push    es              ;If the active PSP has an
  140.         mov    es,bx            ;  environment block at a
  141.         mov    ax,es:[2ch]        ;  higher memory address than
  142.         dec    ax            ;  the PSP, assume that the
  143.         mov    es,ax            ;  the active program is a
  144.         cmp    byte ptr es:[0],"M"    ;  shelled copy of COMMAND.COM
  145.         pop    es
  146.         jne    chkpsp2                 ;Valid memory block?
  147.         cmp    ax,bx            ;Env seg > PSP seg?
  148.         jae    dosint_2        ;Yes, must be shelled copy
  149. chkpsp2:
  150.         pop    bx            ;Cleanup and goto DOS
  151.         pop    ax
  152.         jmp    short goto_dos
  153. dosint_2:
  154.         cld                ;Set direction flag
  155.         mov    cs:[saved_ss],ss    ;Save SS:SP
  156.         mov    cs:[saved_sp],sp
  157.         cli
  158.         push    cs                      ;Move to internal stack
  159.         pop    ss
  160.         mov    sp,cs:[mystack_ptr]
  161.         sti
  162.         push    bp                      ;Save remaining registers.
  163.         mov    bp,sp            ;Set up stack access
  164.         push    cx
  165.         push    dx
  166.         push    di
  167.         push    si
  168.         push    ds
  169.         push    es
  170. ;
  171. ;The call is from COMMAND.COM. Invoke line editor.
  172. ;
  173.         push    dx
  174.         call    cmd_input
  175.         pop    dx
  176.         cmp    cs:[cmdstack_size],0
  177.         je    dosint_3
  178.         call    cmd_record
  179. ;
  180. ;Check for alias before returning to COMMAND.COM
  181. ;
  182. dosint_3:
  183.         cmp    cs:[chk_alias],0         ;See if alias translation
  184.         je    dosint_exit          ;  is enabled.
  185.         mov    si,[bp-4]        ;Get pointer to input buffer
  186.         inc     si
  187.         xor    cx,cx
  188.         or     cl,ds:[si]        ;Get length of buffer
  189.         je    dosint_exit        ;If buffer empty, exit.
  190.         inc    si            ;Point to 1st char in buffer
  191.         mov    ax,cs
  192.         mov    es,ax            ;Set ES to installed code.
  193.         call    searchalias        ;See if an alias is found.
  194.         jc    dosint_exit        ;No, exit.
  195. ;
  196. ;If alias found, copy it from alias list to internal buffer.
  197. ;
  198.         mov     si,di            ;Load SI with alias pointer
  199.         mov    ax,es
  200.         mov    ds,ax            ;Point DS to alias list seg
  201.         xor    cx,cx
  202.         mov    cl,ds:[si+3]        ;Get size of alias
  203.         call    getalias        ;Get alias from list
  204. ;
  205. ;Append remainder of command line to alias if no cmd line parameters were used.
  206. ;
  207.         or    dx,dx            ;See if any command line
  208.         jne    dosint_6        ;  parameters were used.
  209.         push    si            ;Save pointer to buffer.
  210.         push    ds
  211.         mov    di,si
  212.         add    di,cx            ;Point DI to end of alias
  213.         mov    dx,cx            ;Save length of alias
  214.         mov    si,[bp-4]        ;Point DS:SI to command.com
  215.         mov    ds,[bp-10]        ;  data buffer.
  216.         xor    cx,cx
  217.         inc    si
  218.         mov    cl,[si]            ;Get length of command line.
  219.         cmp    ah,cl            ;See if enough space in
  220.         ja    dosint_4        ;  internal buffer. If not
  221.         mov    cl,ah            ;  copy only until buff full.
  222. dosint_4:
  223.         inc    si
  224.         mov    bl,1             ;Skip past alias.
  225.         call    scan4char
  226.         jc    dosint_5
  227.         dec    si            ;Back up 1 char
  228.         inc    cx
  229.         add    dx,cx            ;Add length of command line.
  230.         rep    movsb            ;Copy command line
  231. dosint_5:
  232.         mov    cx,dx            ;Restore length of command
  233.         pop    ds            ;Restore pointer
  234.         pop    si
  235. ;
  236. ;Copy alias from internal buffer to COMMAND.COM data buffer.
  237. ;
  238. dosint_6:
  239.         mov    di,[bp-4]        ;Point ES:DI to command.com
  240.         mov    es,[bp-10]        ;  data buffer.
  241.         mov    al,es:[di]        ;Get size of data buffer
  242.         dec    al            ;If alias longer than buffer,
  243.         cmp    al,cl            ;  copy only the enough
  244.         ja     dosint_7        ;  characters to fill the
  245.         xor    cx,cx            ;  buffer.
  246.         mov     cl,al
  247. dosint_7:
  248.         inc    di            ;Move DI past length bytes
  249.         mov    es:[di],cl        ;Save length of command
  250.         inc    di
  251.         rep    movsb            ;Copy alias.
  252.         mov    byte ptr es:[di],13     ;Append carriage return
  253. dosint_exit:
  254.         mov    cx,cs:[cursor_mode]    ;Set default cursor
  255.         mov    ah,1
  256.         int    10h
  257.         pop    es
  258.         pop    ds
  259.         pop    si
  260.         pop    di
  261.         pop    dx
  262.         pop    cx
  263.         pop    bp
  264.             cli
  265.         mov    ss,cs:[saved_ss]    ;Restore stack pointer
  266.         mov    sp,cs:[saved_sp]
  267.         pop    bx
  268.         pop    ax
  269.         iret                ;Return to COMMAND.COM
  270. dosint        endp
  271.  
  272. ;-----------------------------------------------------------------------------
  273. ; GETALIAS Copies an alias from the alias list while substituting any
  274. ;          environment variables and command line parameters.
  275. ; Entry:  DS:SI - pointer to alias
  276. ; Exit:   DS:SI - pointer to buffer containing translated alias.
  277. ;            AH - free space in buffer
  278. ;            CX - length of the alias
  279. ;-----------------------------------------------------------------------------
  280. getalias    proc    near
  281.         mov    di,work_buff_ptr    ;Point DI to internal buffer
  282.         xor    ax,ax               ;Point to command by adding
  283.         mov    al,ds:[si+2]        ;  the size of the alias to
  284.         add    si,ax               ;  pointer to the entry.
  285.         add    si,4            ;Move past list data.
  286.         mov    ah,126            ;AH contains max size of buff
  287.         xor    dx,dx            ;Clear flag for line params
  288. alias_1:
  289.         lodsb                ;Get byte from alias
  290.         cmp    al,"%"            ;See if special character
  291.         je     alias_3            ;Yes, process special char.
  292. alias_2:
  293.         stosb                ;Store byte from alias
  294.         dec    ah            ;Dec buffer size counter
  295.         jz    alias_6            ;If internal buffer full, done
  296.         loop    alias_1
  297.         jmp    short alias_6        ;If at end of alias, done
  298. ;
  299. ;A percent sign has been found indicating a 'soft' parameter.
  300. ;
  301. alias_3:
  302. ;        mov    al,ds:[si]        ;Get character after %
  303.         lodsb
  304.         dec    cx
  305.         cmp    al,"%"            ;If double %, include in one
  306.         je    alias_2            ;  % in alias.
  307.                 mov    bh,al              ;Copy and check to see if
  308.         sub    bh,"0"            ;  the next char is a number.
  309.         jb    alias_5         ;  If so, assume a line
  310.         cmp    bh,9                    ;  parameter.
  311.         ja    alias_5
  312.          call    sublineparam        ;Substitute a line paramter
  313.         inc    dx
  314. alias_4:
  315.         loop    alias_1
  316.         jmp    short alias_6        ;If at end of alias, done
  317. alias_5:
  318.         dec    si            ;Backup to 1st character
  319.         inc    cx
  320.          call    subenvvar        ;Substitute an environment var
  321.         loop    alias_1
  322. alias_6:
  323.         mov    si,work_buff_ptr    ;Point SI to internal buffer
  324.         mov    cx,di            ;Compute size of completed
  325.         sub    cx,si                     ;  alias.
  326.         ret
  327. getalias    endp
  328.  
  329. ;-----------------------------------------------------------------------------
  330. ; SUBLINEPARAM substitutes a parameter from the command line into the alias.
  331. ; Entry:  DS:SI - pointer to alias
  332. ;         ES:DI - pointer to buffer to copy the line parameter
  333. ;            AH - remaining space in the internal buffer
  334. ;            BH - binary number of the line parameter
  335. ;            CX - length of the alias
  336. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  337. ;         DS:SI - pointer to the character after the line parameter number
  338. ;            CX - remaining length of the alias
  339. ;-----------------------------------------------------------------------------
  340. sublineparam    proc    near
  341.         push    cx
  342.         push    si
  343.         push    ds
  344.         mov    si,[bp-4]        ;Get pointer to command.com
  345.         mov    ds,[bp-10]        ;  data buffer.
  346.         xor    cx,cx
  347.         mov    cl,ds:[si+1]        ;Get number of chars in buffer.
  348.         inc    si            ;Point to the first byte of
  349.         inc    si            ;  data.
  350. sublineparam_1:
  351.         or    bh,bh            ;Check count of param to find.
  352.         jz    sublineparam_2
  353.         mov    bl,1
  354.         call    scan4char        ;Find next space
  355.         jc    sublineparam_exit
  356.         dec    bl
  357.         call    scan4char        ;Find next word
  358.         jc    sublineparam_exit
  359.         dec    bh            ;Dec parameter count
  360.         jne    sublineparam_1        ;If not done, loop back.
  361.         dec    si            ;Backup to 1st char in word.
  362. sublineparam_2:
  363.         lodsb                ;Get character from parameter
  364.         cmp    al," "            ;If space, parameter done
  365.         jbe    sublineparam_exit
  366.         stosb
  367.         dec    ah            ;Dec buffer size counter
  368.         jnz    sublineparam_2
  369. sublineparam_exit:
  370.         pop    ds
  371.         pop    si
  372.         pop    cx
  373.         ret
  374. sublineparam    endp
  375.  
  376. ;-----------------------------------------------------------------------------
  377. ; SUBENVVAR substitutes an environment variable into alias.
  378. ; Entry:  DS:SI - pointer to variable to substitute
  379. ;         ES:DI - pointer to buffer to copy the contents of the variable
  380. ;            AH - remaining space in internal buffer
  381. ;            CX - length of alias string
  382. ; Exit:   DS:SI - pointer to the byte after the variable name
  383. ;         ES:DI - pointer to the byte after the variable contents
  384. ;            CF - set if variable not found
  385. ;-----------------------------------------------------------------------------
  386. subenvvar      proc    near
  387.         push    dx
  388.         push    ds
  389.         push    es
  390. ;
  391. ;Compute the length of the variable name.
  392. ;
  393.         mov    bx,di                    ;Save pointer to internal buff
  394.         mov    di,si                   ;Compute the length of the
  395.         mov      dx,cx                   ;  environment variable by
  396.         mov    al,"%"                  ;  searching for the trailing
  397.         repne    scasb                   ;  % sign.
  398.         sub    dx,cx            ;Compute length of variable.
  399.         dec    dx            ;Subtract % byte fron length.
  400.         push    di            ;Save ptr to end of env var.
  401. ;
  402. ;Search the Master Environment block for the variable pointed to by DS:SI
  403. ;
  404.         mov    es,cs:[master_env]    ;Get segment of master env blk
  405.         xor    di,di            ;Point ES:DI to environment.
  406.         push    cx            ;Save alias size.
  407.         push    bx            ;Save ptr to internal buffer
  408.         mov     bx,si            ;Save pointer to var name
  409. subenvvar_1:
  410.         mov    si,bx            ;Get back ptr to var name.
  411.         mov    cx,dx            ;Compare env var to var in
  412.         repe    cmpsb                   ;  alias.
  413.         je    subenvvar_2        ;Variable found, exit loop
  414.         xor    al,al            ;Find next environment var.
  415.         mov    cx,-1              ;Scan the entire segment.
  416.         repne    scasb
  417.         cmp    byte ptr es:[di],0    ;If double zero, end of env
  418.         jne    subenvvar_1        ;  block. else, loop back.
  419.         pop    di                      ;Restore DI and exit
  420.         jmp    short subenvvar_exit
  421. ;
  422. ;Environment variable found. Substitute into alias.
  423. ;
  424. subenvvar_2:
  425.         mov    si,es            ;DS:SI points to env string
  426.         mov    ds,si            ;ES:DI points to internal buff
  427.         mov     si,cs
  428.         mov    es,si
  429.         mov    si,di            ;Copy pointer to var contents.
  430.         pop    di               ;Restore ptr to internal buff
  431. subenvvar_3:
  432.         lodsb                ;Move environment pointer past
  433.         cmp    al,"="            ;  the equals sign.
  434.         jne    subenvvar_3
  435. subenvvar_4:
  436.         lodsb                ;Move pointer to first
  437.         cmp    al," "            ;  non-space character.
  438.         jb    subenvvar_4
  439. subenvvar_5:
  440.         or    al,al            ;See if at the end of variable
  441.         je    subenvvar_exit
  442.         stosb                ;Save character in command
  443.         lodsb                ;Get next character
  444.         dec    ah            ;Dec buffer size count.
  445.         jne    subenvvar_5        ;If buffer not full, continue
  446. subenvvar_exit:
  447.         pop    cx            ;Restore alias length
  448.         pop    si            ;Restore alias pointer
  449.         pop    es            ;Restore segment registers
  450.         pop    ds
  451.         pop    dx
  452.         ret
  453. subenvvar    endp
  454.  
  455. ;-----------------------------------------------------------------------------
  456. ; SUBKEY searches the alias list for a key substitution
  457. ; Entry:  AL - extended key code
  458. ; Exit:   CF - clear if key found, set if not found
  459. ;         DX - offset address of matching entry in alias list (if CF = 0)
  460. ;         CX - length of matching entry (if CF = 0)
  461. ;-----------------------------------------------------------------------------
  462. subkey        proc    near
  463.         push    bx
  464.         push    di
  465.         push    si
  466.         push    ds
  467.         push    es
  468.                 xor    ah,ah            ;Indicate extended code.
  469.         les    di,cs:[aliaslist_ptr]    ;Get pointer to alias list.
  470. subkey_1:
  471.         mov    dx,es:[di]        ;Get next entry offset
  472.         cmp    dx,-1            ;See if at the end of the list
  473.         je    subkey_notfound
  474.         cmp    es:[di+4],ax        ;Check for key code.
  475.         je    subkey_found        ;If found, exit loop
  476. subkey_2:
  477.         add    di,dx             ;Else, point to next entry.
  478.         jmp    short subkey_1
  479. ;
  480. ;Copy alias into internal buffer.
  481. ;
  482. subkey_found:
  483.         mov     si,di            ;Load SI with alias pointer
  484.         mov    ax,es
  485.         mov    ds,ax            ;Point DS to alias list seg
  486.         xor    cx,cx
  487.         mov    cl,ds:[si+3]        ;Get size of alias
  488.         call    getalias        ;Get alias from list
  489.         mov    dx,si            ;Copy pointer to buffer
  490.         clc                ;Set key found flag
  491. subkey_exit:
  492.         pop    es
  493.         pop    ds
  494.         pop    si
  495.         pop    di
  496.         pop    bx
  497.         ret
  498. subkey_notfound:
  499.         stc                ;Set key not found flag
  500.         jmp    subkey_exit
  501. subkey        endp
  502.  
  503. ;-----------------------------------------------------------------------------
  504. ; SEARCHALIAS searches the alias list for a matching alias.
  505. ; Entry:  DS:SI - pointer to alias
  506. ;            ES - segment of installed code
  507. ;            CX - length input buffer
  508. ; Exit:      CF - clear if alias found
  509. ;         ES:DI - pointer to matching entry in alias list, if CF is clear
  510. ;-----------------------------------------------------------------------------
  511. searchalias    proc    near
  512.         push    bx            ;Save registers
  513.         push    cx
  514.         push    si
  515.         xor    bx,bx
  516. searchalias_1:
  517.         lodsb                           ;Compute the length of the
  518.         or     al,al                   ;  length of the alias by
  519.         je    searchalias_2             ;  finding the next space.
  520.         cmp    al," "                  ;Allow zero byte in alias
  521.         jbe    searchalias_3           ;  for function key labels.
  522. searchalias_2:
  523.         inc    bx
  524.          loop    searchalias_1
  525. searchalias_3:
  526.         pop    si
  527.         les    di,es:[aliaslist_ptr]    ;Get pointer to alias list.
  528.         mov    cx,bx            ;Get length of alias
  529. searchalias_4:
  530.         mov    bx,es:[di]
  531.         cmp    bx,-1            ;See if at the end of the list
  532.         je    searchalias_notfound
  533.         cmp    es:[di+2],cl        ;Compare lengths
  534.         jne    searchalias_5
  535.         push    cx            ;Save size and starting
  536.         push    di                      ;  pointers.
  537.         push    si
  538.         add    di,4            ;Point to start of alias field.
  539.         repe    cmpsb            ;Compare alias to input string
  540.         pop    si
  541.         pop    di
  542.         pop    cx
  543.         je    searchalias_6        ;If found, exit loop
  544. searchalias_5:
  545.         add    di,bx            ;Else, point to next entry.
  546.         jmp    short searchalias_4
  547. searchalias_6:
  548.         clc                ;Set alias found flag
  549. searchalias_exit:
  550.         pop    cx
  551.         pop    bx
  552.         ret
  553. searchalias_notfound:
  554.         stc
  555.         jmp    short searchalias_exit
  556. searchalias    endp
  557.  
  558. ;-----------------------------------------------------------------------------
  559. ; SCAN4CHAR scans a string to find the first character.
  560. ; Entry:  SI - pointer to ASCII string
  561. ;         BL - 0 = find next char, 1 = find next space
  562. ;         CX - file length
  563. ; Exit:   AL - first nonspace character
  564. ;         CF - set if carriage return found
  565. ;-----------------------------------------------------------------------------
  566. scan4char      proc near
  567.         assume    ds:nothing,es:nothing
  568. scan4loop:
  569.         jcxz    scan4_eol        ;See if at the end of the file.
  570.         lodsb
  571.         dec    cx                 ;Decrement file length counter.
  572.         cmp    al,13            ;Check for carriage return.
  573.         jne    scan4_1
  574. scan4_eol:
  575.         stc
  576.         jmp    short scan4_exit1
  577. scan4_1:
  578.         or    bl,bl            ;Check if searching for space
  579.         jne    scan4_2            ;  or character.
  580.         cmp    al," "            ;Check for space or other
  581.         jbe    scan4loop        ;  'white' characters.
  582.         jmp    short scan4_exit
  583. scan4_2:
  584.         cmp    al," "            ;Check for characters.
  585.         ja    scan4loop
  586. scan4_exit:
  587.         clc
  588. scan4_exit1:
  589.          ret
  590. scan4char    endp
  591.  
  592. ;----------------------------------------------------------------------------
  593. ; CMD_INPUT replaces DOS' 0Ah text input function.
  594. ;----------------------------------------------------------------------------
  595. cmd_input    proc    near
  596.         push    ds            ;Save DS
  597.         xor    ax,ax            ;Then zero it
  598.         mov    ds,ax
  599.         mov    ax,ds:[0485h]        ;Get number of scan lines
  600.         cmp    ax,cs:[points]        ;  per character and branch
  601.         je    cmd1            ;  if it hasn't changed
  602.  
  603.         mov    cs:[points],ax        ;Record new number of scan
  604.         mov    ax,ds:[0460h]        ;  lines per character and
  605.         mov    cs:[cursor_mode],ax    ;  cursor mode
  606. cmd1:
  607.         pop    ds            ;Restore DS
  608.         call    set_cursor        ;Set cursor mode
  609.  
  610.         mov    ah,15            ;Get video page and columns
  611.         int    10h
  612.         dec    ah            ;Calculate max column number
  613.         mov    cs:[columns],ah        ;Save it
  614.         mov    ax,ds            ;Point ES:DI to buffer
  615.         mov    es,ax
  616.         mov    di,dx
  617.         add    di,2
  618.         mov    si,dx            ;Point DS:SI to character count
  619.         inc    si
  620.         mov    byte ptr [si],0        ;Zero initial count
  621.         mov    cs:[bufferptr],1    ;Set initial index value
  622.         cld                ;Clear DF
  623. ;
  624. ;Wait for a keycode to appear in the keyboard buffer.
  625. ;
  626. getkey:        mov    ah,0Bh            ;Check buffer for keycode
  627.         int    21h
  628.         or    al,al            ;Anything there?
  629.         jne    getchar            ;Yes, then go get it
  630.         int    28h            ;No, then execute interrupt 28h
  631.         jmp    getkey            ;Loop back for another try
  632. ;
  633. ;Read the keycode and process it if it's not an extended code.
  634. ;
  635. getchar:
  636.         mov    ah,8            ;Read character from buffer
  637.         int    21h
  638.         or    al,al            ;Is it an extended code?
  639.         je    excode            ;Yes, then branch
  640.  
  641.         cmp    al,8            ;Backspace key?
  642.         jne    getc1            ;No, then branch
  643.         call    backspace        ;Rub out a character
  644.         jmp    getkey            ;Return to loop
  645. getc1:
  646.         cmp    al,9            ;Tab key?
  647.         jne    getc2            ;No, then branch
  648.         call    tab            ;Tab to next tab boundary
  649.         jmp    getkey            ;Return to loop
  650. getc2:
  651.         cmp    al,27            ;ESC key?
  652.         jne    getc3            ;No, then branch
  653.         call    clear_line        ;Yes, then clear input line
  654.         mov    cs:[cmd_ptr],0        ;Zero current command pointer
  655.         jmp    getkey
  656. getc3:
  657.         cmp    al,7Fh            ;Ctrl-Backspace?
  658.         jne    getc4            ;No, then branch
  659.         call    ctrl_bs            ;Yes, then delete word
  660.         jmp    getkey
  661. getc4:
  662.         cmp    al,13            ;ENTER key?
  663.         je    enter            ;Yes, then branch
  664.         call    printchar        ;No, then print the character
  665. getc5:
  666.         jmp    getkey
  667. enter:
  668.         call    eol            ;Place cursor at end-of-line
  669.         mov    byte ptr es:[di],13    ;Insert carriage return code
  670.         mov    ah,2            ;Advance to next line
  671.         mov    dl,13
  672.         int    21h
  673. get_exit:
  674.         ret
  675. ;
  676. ;Process extended keycodes.
  677. ;
  678. excode:
  679.         mov    ah,8            ;Read extended code
  680.         int    21h
  681.  
  682.                 cmp    al,3Bh            ;See if below F1
  683.         jb    excode3
  684.         cmp    al,71h            ;See if above Alt-F10
  685.         ja    excode3
  686.                 cmp    al,54h            ;See if above Shift-F1
  687.         jae    excode1
  688.         cmp    al,44h            ;See if above F10
  689.         ja    excode3
  690. excode1:
  691.         call    subkey            ;Scan alias list for match
  692.         jc    getkey            ;Exit if no match found
  693.         push    cx
  694.         push    dx
  695.         call    clear_line        ;Clear command line
  696.         pop    dx
  697.         pop    cx
  698. excode2:
  699.         push    si
  700.         mov    si,dx            ;Copy offset address into SI
  701.         mov    al,byte ptr cs:[si]    ;Get next character
  702.         pop    si
  703.         cmp    al,13            ;Exit and execute command
  704.         je    enter            ;  on carriage return
  705.         inc    dx
  706.         push    cx
  707.         push    dx
  708.         call    printchar        ;Print it
  709.         pop    dx
  710.         pop    cx
  711.         jc    getc5
  712.         loop    excode2            ;Loop until done
  713.         jmp    getkey            ;Return to input loop
  714. excode3:
  715.         push    es            ;Save buffer address
  716.         push    di
  717.         mov    cx,cs            ;Point ES:DI to list of
  718.         mov    es,cx            ;  supported keycodes
  719.         mov    di,offset exkeys
  720.         mov    cx,offset exkeys_end - offset exkeys
  721.         repne    scasb            ;Scan list
  722.         pop    di            ;Clear the stack
  723.         pop    es
  724.         jne    excode4            ;Ignore if key not found
  725.         shl    cx,1            ;Convert CX to address
  726.         add    cx,offset ex_entry
  727.         push    bx            ;Save page number in BH
  728.         mov    bx,cx            ;Get entry address from table
  729.         mov    ax,cs:[bx]
  730.         pop    bx            ;Restore BH
  731.         call    ax            ;Call handling routine
  732. excode4:
  733.         jmp    getkey            ;Return to input loop
  734. cmd_input    endp
  735.  
  736. ;------------------------------------------------------------------------------
  737. ; PREV_CMD outputs the previous command in the command stack.
  738. ;------------------------------------------------------------------------------
  739. prev_cmd    proc    near
  740.         mov    dx,cs:[cmd_ptr]        ;Get current stack index
  741.         cmp    dx,cs:[cmdstack_size]    ;Exit if at top of command
  742.         je    prev_exit        ;  stack
  743.         or    dx,dx            ;Branch if not at bottom of
  744.         jnz    prev1            ;  command stack
  745. ;
  746. ;Copy the current contents of the command line to the search buffer.
  747. ;
  748.         mov    cl,[si]            ;Get count of characters on
  749.         xor    ch,ch            ;  command line in CX
  750.         inc    cx
  751.         push    es            ;Save registers
  752.         push    di
  753.         push    si
  754.         mov    ax,cs            ;Point ES:DI to search text
  755.         mov    es,ax            ;  buffer
  756.         mov    di,offset command_tail
  757.         rep    movsb            ;Copy command line text
  758.         pop    si            ;Restore registers
  759.         pop    di
  760.         pop    es
  761. ;
  762. ;Search for the previous command and output it.
  763. ;
  764. prev1:
  765.         inc    dx            ;Increment stack index
  766.         mov    ax,cs:[next_ptr]    ;Get stack base index
  767.         sub    ax,dx            ;Calculate address of previous
  768.         cmp    ax,0            ;  command
  769.         jge    prev2
  770.         add    ax,cs:[cmdstack_size]
  771. prev2:
  772.         mov    cl,7            ;Calculate offset address of
  773.         shl    ax,cl            ;  the command
  774.         add    ax,cs:[cmdstack_base]
  775.         cmp    byte ptr cs:[command_tail],0    ;Output command if there is
  776.         je    prev3            ;  no search criterion
  777.         call    check_string        ;Compare strings
  778.         jz    prev3            ;Output command if the strings
  779.         cmp    dx,cs:[cmdstack_size]    ;  match
  780.         jne    prev1
  781.         ret                ;Exit if at top of stack
  782. prev3:
  783.         push    si            ;Save SI
  784.         mov    si,ax            ;Transfer address to SI
  785.         cmp    byte ptr cs:[si],0    ;Valid command?
  786.         pop    si            ;Restore SI
  787.         je    prev_exit        ;No, then ignore keypress
  788.         mov    cs:[cmd_ptr],dx        ;Save new command pointer
  789.         call    write_command        ;Output the command string
  790. prev_exit:
  791.         ret
  792. prev_cmd    endp
  793.  
  794. ;------------------------------------------------------------------------------
  795. ; NEXT_CMD outputs the next command in the command stack.
  796. ;------------------------------------------------------------------------------
  797. next_cmd    proc    near
  798.         mov    dx,cs:[cmd_ptr]        ;Get current stack index
  799.         or    dx,dx            ;Exit if it's zero
  800.         jz    next_exit
  801. next1:
  802.         dec    dx            ;Decrement stack index
  803.         mov    cs:[cmd_ptr],dx        ;Save command pointer
  804.         or    dx,dx            ;Clear line and exit if
  805.         jz    next3            ;  the result is zero
  806.         mov    ax,cs:[next_ptr]    ;Get stack base index
  807.         sub    ax,dx            ;Calculate address of next
  808.         cmp    ax,0            ;  command
  809.         jge    next2
  810.         add    ax,cs:[cmdstack_size]
  811. next2:
  812.         mov    cl,7            ;Calculate offset address of
  813.         shl    ax,cl            ;  command
  814.         add    ax,cs:[cmdstack_base]
  815.         cmp    byte ptr cs:[command_tail],0    ;Output command if there is
  816.         je    next4            ;  no search criterion
  817.         call    check_string        ;Compare strings
  818.         jz    next4            ;Output command if the strings
  819.         jmp    next1            ;  match
  820. next3:
  821.         call    clear_line
  822.         cmp    byte ptr cs:[command_tail],0
  823.         je    next_exit
  824.         mov    ax,offset command_tail
  825. next4:
  826.         call    write_command        ;Output the command string
  827. next_exit:
  828.         ret
  829. next_cmd    endp
  830.  
  831. ;------------------------------------------------------------------------------
  832. ; CHECK_STRING compares the string in the search buffer with another string.
  833. ; Entry:  AX - string address
  834. ; Exit:   ZF - set if strings are equivalent, clear if they are not
  835. ;------------------------------------------------------------------------------
  836. check_string    proc    near
  837.         push    ds            ;Save registers
  838.         push    si
  839.         push    es
  840.         push    di
  841.         mov    cx,cs            ;Point DS and ES to
  842.         mov    ds,cx            ;  code segment
  843.         mov    es,cx
  844.         mov    si,offset command_tail    ;Point DS:SI to text in
  845.         mov    cl,[si]            ;  search buffer
  846.         xor    ch,ch
  847.         inc    si
  848.         mov    di,ax            ;Point DI to other string
  849.         inc    di            ;
  850.         repe    cmpsb            ;Compare strings
  851.         pop    di            ;Restore registers
  852.         pop    es
  853.         pop    si
  854.         pop    ds
  855.         ret
  856. check_string    endp
  857.  
  858. ;------------------------------------------------------------------------------
  859. ; PRINT_STRING writes an ASCII string to the command line.
  860. ; Entry:  DS:SI - string address
  861. ;            CX - number of characters
  862. ;------------------------------------------------------------------------------
  863. print_string    proc    near
  864.         jcxz    ps_exit            ;Exit if no characters
  865.         push    dx
  866.         cld
  867.         mov    ah,2            ;Print the character
  868. ps1:
  869.         lodsb                ;Get a byte
  870.         mov    dl,al            ;Transfer it to DL
  871.         int    21h            ;Output character
  872.         loop    ps1            ;Loop until done
  873.         pop    dx
  874. ps_exit:
  875.         ret
  876. print_string    endp
  877.  
  878. ;------------------------------------------------------------------------------
  879. ; WRITE_COMMAND outputs a command string.
  880. ; Entry:  AX - string offset address
  881. ; Exit:   AL - character after string
  882. ;------------------------------------------------------------------------------
  883. write_command    proc    near
  884.         push    ax            ;Save address
  885.         call    clear_line        ;Clear input line
  886.         pop    ax            ;Retrieve string address
  887.         push    ds            ;Save DS and SI
  888.         push    si
  889.         push    cs            ;Point DS to string segment
  890.         pop    ds
  891.         mov    si,ax            ;Point SI to the string
  892.         mov    cl,[si]            ;Get string length
  893.         xor    ch,ch
  894.         mov    byte ptr es:[di-1],cl    ;Store string length
  895.         inc    si            ;Advance SI to string text
  896. write1:
  897.         mov    ah,2            ;Print one character
  898.         mov    dl,[si]
  899.         int    21h
  900.         movsb                ;Transfer character to buffer
  901.         inc    cs:[bufferptr]        ;Advance pointer
  902.         loop    write1            ;Loop until done
  903.         lodsb                ;Get first character after string
  904.         pop    si            ;Restore registers
  905.         pop    ds
  906.         ret
  907. write_command    endp
  908.  
  909. ;------------------------------------------------------------------------------
  910. ; TOGGLE_INS toggles the insert flag.
  911. ;------------------------------------------------------------------------------
  912. toggle_ins    proc    near
  913.         xor    cs:[insert_flag],1    ;Toggle insert flag
  914.         call    set_cursor        ;Set cursor mode
  915.         ret
  916. toggle_ins    endp
  917.  
  918. ;------------------------------------------------------------------------------
  919. ; TAB tabs to the next tab boundary.
  920. ;------------------------------------------------------------------------------
  921. tab        proc    near
  922.         mov    al,cs:[bufferptr]    ;Calculate number of
  923.         dec    al            ;  spaces to insert for
  924.         xor    ah,ah            ;  soft tab
  925.         mov    bl,8
  926.         div    bl
  927.         mov    cx,8
  928.         sub    cl,ah
  929. tab1:
  930.         push    cx            ;Print spaces
  931.         mov    al,32
  932.         call    printchar
  933.         pop    cx
  934.         jc    tab_exit
  935.         loop    tab1
  936. tab_exit:
  937.         ret
  938. tab        endp
  939.  
  940. ;------------------------------------------------------------------------------
  941. ; BACKSPACE deletes the character left of the cursor.
  942. ;------------------------------------------------------------------------------
  943. backspace    proc    near
  944.         cmp    cs:[bufferptr],1    ;At beginning of command line?
  945.         je    bs_exit            ;Yes, then ignore it
  946.         mov    cl,[si]            ;Get count
  947.         sub    cl,cs:[bufferptr]    ;Calculate distance to end-of-line
  948.         inc    cl
  949.         xor    ch,ch
  950.         push    cx            ;Save it
  951.         jcxz    bs1            ;Branch if at end-of-line
  952. ;
  953. ;Shift all characters right of the cursor in the buffer one slot left.
  954. ;
  955.         push    si            ;Save SI and DI
  956.         push    di
  957.         mov    si,di            ;Position them for shifts
  958.         dec    di
  959.         rep    movsb            ;Shift characters right of cursor
  960.         pop    di            ;Restore registers
  961.         pop    si
  962. ;
  963. ;Display the new string and update input parameters.
  964. ;
  965. bs1:
  966.         call    move_left        ;Move cursor left
  967. bs2:
  968.         pop    cx            ;Retrieve shift count
  969.         push    dx            ;Save cursor position
  970.         push    si            ;Save SI
  971.         mov    si,di            ;Point SI to new part of string
  972.         call    print_string        ;Print the new part
  973.         mov    ah,2            ;Blank the last character
  974.         mov    dl,32
  975.         int    21h
  976.         pop    si            ;Restore registers
  977.         pop    dx            ;Restore cursor address
  978.         mov    ah,2            ;Reset the cursor
  979.         int    10h
  980.         dec    byte ptr [si]        ;Decrement character count
  981. bs_exit:
  982.         ret
  983. backspace    endp
  984.  
  985. ;------------------------------------------------------------------------------
  986. ; PRINTCHAR writes a new character to the input buffer and echoes it.
  987. ; Entry:  AL - character to print
  988. ; Exit:   CF clear if character printed
  989. ;         CF set if buffer full
  990. ;------------------------------------------------------------------------------
  991. printchar    proc    near
  992.         cmp    cs:[insert_flag],0    ;Insert state on?
  993.         jne    print3            ;Yes, then branch
  994. ;
  995. ;Print a character in overstrike mode.
  996. ;
  997.         mov    cl,[si]            ;Get count
  998.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  999.         jae    print2            ;No, then branch
  1000.         mov    cl,[si-1]        ;Get maximum length
  1001.         sub    cl,[si]            ;Subtract current length
  1002.         cmp    cl,1            ;Buffer full?
  1003.         je    beep            ;Yes, then branch
  1004. print1:
  1005.         inc    byte ptr [si]        ;Increment count
  1006. print2:
  1007.         stosb                ;Deposit new character
  1008.         mov    ah,2            ;Then print it
  1009.         mov    dl,al
  1010.         int    21h
  1011.         inc    cs:[bufferptr]        ;Advance buffer pointer
  1012. print_exit:
  1013.         clc                ;Clear CF and exit
  1014.         ret
  1015. beep:
  1016.         mov    ax,0E07h        ;Print ASCII 7 thru BIOS
  1017.         int    10h
  1018.         stc
  1019.         ret
  1020. ;
  1021. ;Print a character in insert mode.
  1022. ;
  1023. print3:
  1024.         mov    cl,[si-1]        ;Get maximum length
  1025.         sub    cl,[si]            ;Subtract current count
  1026.         cmp    cl,1            ;Buffer full?
  1027.         je    beep            ;Yes, then branch
  1028.         mov    cl,[si]            ;Get count
  1029.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1030.         jb    print1            ;Yes, then branch
  1031.         sub    cl,cs:[bufferptr]    ;Calculate number of shifts
  1032.         inc    cl
  1033.         xor    ch,ch
  1034.         push    cx            ;Save shift count
  1035.         push    si            ;Save SI
  1036.         add    di,cx            ;Position DI to end-of-line
  1037.         mov    si,di            ;Position SI just before it
  1038.         dec    si
  1039.         std                ;Set DF for now
  1040.         rep    movsb            ;Make room for new character
  1041.         cld                ;Clear DF
  1042.         pop    si            ;Restore SI
  1043.         mov    es:[di],al        ;Deposit new character
  1044.         mov    ah,3            ;Get cursor position
  1045.         int    10h
  1046.         pop    cx            ;Retrieve shift count
  1047.         inc    cx            ;Increment it
  1048.         push    dx            ;Save cursor position
  1049.         push    si            ;Save SI
  1050.         mov    si,di            ;Point SI to current location
  1051.         call    print_string        ;Print new part of string
  1052.         pop    si            ;Restore SI and DX
  1053.         pop    dx
  1054.         mov    ah,2            ;Reset cursor position
  1055.         int    10h
  1056.         inc    byte ptr [si]        ;Add to character count
  1057.         call    move_right        ;Move cursor right
  1058.         jmp    print_exit
  1059. printchar    endp
  1060.  
  1061. ;------------------------------------------------------------------------------
  1062. ; DELETE deletes the character at the cursor.
  1063. ;------------------------------------------------------------------------------
  1064. delete        proc    near
  1065.         mov    cl,[si]            ;Get count
  1066.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1067.         jb    del2            ;Yes, then ignore keypress
  1068.         sub    cl,cs:[bufferptr]    ;Calculate number of shifts
  1069.         xor    ch,ch            ;Byte to word in CX
  1070.         push    cx            ;Save shift count
  1071.         jcxz    del1            ;Branch if no shifts
  1072.         push    si            ;Save SI and DI
  1073.         push    di
  1074.         mov    si,di            ;Position registers for shift
  1075.         inc    si
  1076.         rep    movsb            ;Shift chars right of cursor
  1077.         pop    di            ;Restore registers
  1078.         pop    si
  1079. del1:
  1080.         mov    ah,3            ;Get cursor position
  1081.         int    10h
  1082.         jmp    bs2            ;Exit thru BACKSPACE routine
  1083. del2:
  1084.         ret
  1085. delete        endp
  1086.  
  1087. ;------------------------------------------------------------------------------
  1088. ; CTRL_BS deletes the word at the cursor.
  1089. ;------------------------------------------------------------------------------
  1090. lesschars    dw    ?            ;Count of chars deleted
  1091. shiftcount    dw    ?            ;Count of chars shifted
  1092.  
  1093. ctrl_bs        proc    near
  1094.         mov    cl,[si]            ;Exit now if there is nothing
  1095.         xor    ch,ch            ;  on the command line
  1096.         or    cx,cx
  1097.         jnz    cbs1
  1098. cbs_exit:
  1099.         ret
  1100. cbs1:
  1101.         cmp    cs:[bufferptr],1    ;Exit if the cursor is at the
  1102.         je    cbs3            ;  at the end of the command
  1103.         cmp    cl,cs:[bufferptr]    ;  line or if it is under a
  1104.         jb    cbs_exit        ;  space; otherwise, move to
  1105.         cmp    byte ptr [di],32    ;  the beginning of the
  1106.         je    cbs_exit        ;  current word
  1107.         cmp    byte ptr [di-1],32
  1108.         je    cbs3
  1109. cbs2:
  1110.         push    cx            ;Save CX
  1111.         call    ctrl_left        ;Move to start of word
  1112.         pop    cx            ;Restore CX
  1113. cbs3:
  1114.         inc    cx            ;Calculate max number of
  1115.         push    cx            ;  characters to search
  1116.         mov    dl,cs:[bufferptr]    ;  looking for the next
  1117.         xor    dh,dh            ;  word or end-of-line
  1118.         sub    cx,dx
  1119.         push    di            ;Save DI
  1120. cbs4:
  1121.         inc    di            ;Search until DI addresses
  1122.         cmp    byte ptr [di],32    ;  either the first character
  1123.         je    cbs5            ;  in the next word or the
  1124.         cmp    byte ptr [di-1],32    ;  end of the command line
  1125.         je    cbs6
  1126. cbs5:
  1127.         loop    cbs4
  1128. cbs6:
  1129.         mov    dx,di            ;Save final value of DI
  1130.         pop    di            ;Restore DI
  1131.         pop    cx            ;Retrieve count
  1132.         mov    cs:[lesschars],dx    ;Calculate number of chars to
  1133.         sub    cs:[lesschars],di    ;  be deleted
  1134.         sub    cx,dx            ;Then calculate how many chars
  1135.         add    cx,si            ;  must be shifted
  1136.         mov    cs:[shiftcount],cx
  1137.         jcxz    cbs7            ;Branch if no shift
  1138.         push    si            ;Save registers
  1139.         push    di
  1140.         mov    si,dx            ;Point DS:SI to next word
  1141.         rep    movsb            ;Delete current word
  1142.         pop    di            ;Restore registers
  1143.         pop    si
  1144. cbs7:
  1145.         mov    cx,cs:[lesschars]    ;Update character counter
  1146.         sub    [si],cl            ;  in input buffer
  1147.         mov    ah,3            ;Save the current cursor
  1148.         int    10h            ;  position on the stack
  1149.         push    dx
  1150.         push    si            ;Update the text on the
  1151.         mov    si,di            ;  command line
  1152.         mov    cx,cs:[shiftcount]
  1153.         call    print_string
  1154.         pop    si
  1155.         mov    cx,cs:[lesschars]
  1156. cbs8:
  1157.         mov    ah,2            ;Print as many spaces as
  1158.         mov    dl,32            ;  there were characters
  1159.         int    21h            ;  deleted
  1160.         loop    cbs8
  1161.         pop    dx            ;Restore cursor position
  1162.         mov    ah,2            ;  and exit
  1163.         int    10h
  1164.         ret
  1165. ctrl_bs        endp
  1166.  
  1167. ;------------------------------------------------------------------------------
  1168. ; CTRL_END deletes command line text from the cursor to the end of the line.
  1169. ;------------------------------------------------------------------------------
  1170. ctrl_end    proc    near
  1171.         mov    cl,[si]            ;Exit if already at end
  1172.         cmp    cl,cs:[bufferptr]    ;  of line
  1173.         jb    ce_exit
  1174.         sub    cl,cs:[bufferptr]    ;Calculate number of chars
  1175.         xor    ch,ch            ;  to be deleted
  1176.         inc    cx
  1177.         sub    [si],cl            ;Update count in input buffer
  1178.         push    cx
  1179.         mov    ah,3            ;Get and save cursor position
  1180.         int    10h
  1181.         pop    cx
  1182.         push    dx
  1183. ce1:
  1184.         mov    ah,2            ;Print as many spaces as
  1185.         mov    dl,32            ;  there are characters
  1186.         int    21h            ;  to delete
  1187.         loop    ce1
  1188.         mov    ah,2            ;Reset cursor position and
  1189.         pop    dx            ;  exit
  1190.         int    10h
  1191. ce_exit:
  1192.         ret
  1193. ctrl_end    endp
  1194.  
  1195. ;------------------------------------------------------------------------------
  1196. ; MOVE_LEFT moves the cursor one character left.
  1197. ;------------------------------------------------------------------------------
  1198. move_left    proc    near
  1199.         cmp    cs:[bufferptr],1    ;At beginning of line?
  1200.         je    left2            ;Yes, then ignore keypress
  1201.         mov    ah,3            ;Get cursor position
  1202.         int    10h
  1203.         dec    dl            ;Decrement it by 1
  1204.         cmp    dl,0FFh
  1205.         jne    left1
  1206.         mov    dl,cs:[columns]        ;Decrement row number by 1
  1207.         dec    dh            ;  if cursor wraps around
  1208. left1:
  1209.         mov    ah,2            ;Set new position
  1210.         int    10h
  1211.         dec    di            ;Decrement pointers
  1212.         dec    cs:[bufferptr]
  1213. left2:
  1214.         ret
  1215. move_left    endp
  1216.  
  1217. ;------------------------------------------------------------------------------
  1218. ; MOVE_RIGHT moves the cursor one character right.
  1219. ;------------------------------------------------------------------------------
  1220. move_right    proc    near
  1221.         mov    cl,[si]            ;Get count
  1222.         cmp    cl,cs:[bufferptr]    ;End-of-line?
  1223.         jb    rt2            ;Yes, then ignore keypress
  1224.         mov    ah,3            ;Get cursor position
  1225.         int    10h
  1226.         inc    dl            ;Increment column number
  1227.         cmp    dl,cs:[columns]        ;Increment row number if
  1228.         jna    rt1            ;  cursor wraps around
  1229.         xor    dl,dl
  1230.         inc    dh
  1231. rt1:
  1232.         mov    ah,2            ;Position cursor
  1233.         int    10h
  1234.         inc    di            ;Advance pointers
  1235.         inc    cs:[bufferptr]
  1236. rt2:
  1237.         ret
  1238. move_right    endp
  1239.  
  1240. ;------------------------------------------------------------------------------
  1241. ; CTRL_LEFT moves the cursor one word left.
  1242. ;------------------------------------------------------------------------------
  1243. ctrl_left    proc    near
  1244.         call    move_left        ;Move one character left
  1245.         cmp    cs:[bufferptr],1    ;Beginning of line?
  1246.         je    cl_exit            ;Yes, then exit
  1247.         cmp    byte ptr es:[di],32    ;Loop back if current char
  1248.         je    ctrl_left        ;  is a space
  1249.         cmp    byte ptr es:[di-1],32    ;Loop back if char to the
  1250.         jne    ctrl_left        ;  left is not a space
  1251. cl_exit:
  1252.         ret
  1253. ctrl_left    endp
  1254.  
  1255. ;------------------------------------------------------------------------------
  1256. ; CTRL_RIGHT moves the cursor one word right.
  1257. ;------------------------------------------------------------------------------
  1258. ctrl_right    proc    near
  1259.         call    move_right        ;Move one character right
  1260.         mov    cl,[si]            ;End-of-line?
  1261.         cmp    cl,cs:[bufferptr]    ;Yes, then exit
  1262.         jb    cr_exit
  1263.         cmp    byte ptr es:[di],32    ;Loop back if current char
  1264.         je    ctrl_right        ;  is a space
  1265.         cmp    byte ptr es:[di-1],32    ;Loop back if char to the
  1266.         jne    ctrl_right        ;  left is not a space
  1267. cr_exit:
  1268.         ret
  1269. ctrl_right    endp
  1270.  
  1271. ;------------------------------------------------------------------------------
  1272. ; HOME relocates the cursor to the beginning of the command line.
  1273. ;------------------------------------------------------------------------------
  1274. home        proc    near
  1275.         mov    cl,cs:[bufferptr]    ;Get position pointer
  1276.         dec    cl            ;Calculate distance from start
  1277.         xor    ch,ch
  1278.         jcxz    home_exit        ;Exit if already there
  1279. home1:
  1280.         push    cx            ;Save count
  1281.         call    move_left        ;Move left one space
  1282.         pop    cx            ;Retrieve count
  1283.         loop    home1            ;Loop until done
  1284. home_exit:
  1285.         ret
  1286. home        endp
  1287.  
  1288. ;------------------------------------------------------------------------------
  1289. ; EOL advances the cursor to the end of the command line.
  1290. ;------------------------------------------------------------------------------
  1291. eol        proc    near
  1292.         mov    cl,[si]            ;Get count
  1293.         cmp    cl,cs:[bufferptr]    ;Already at end?
  1294.         jb    eol_exit        ;Yes, then exit
  1295.         sub    cl,cs:[bufferptr]    ;Calculate distance from end
  1296.         inc    cl
  1297.         xor    ch,ch            ;Byte to word in CX
  1298. eol1:
  1299.         push    cx            ;Advance right CX times
  1300.         call    move_right
  1301.         pop    cx
  1302.         loop    eol1
  1303. eol_exit:
  1304.         ret
  1305. eol        endp
  1306.  
  1307. ;------------------------------------------------------------------------------
  1308. ; CLEAR_LINE clears the command line.
  1309. ; Entry:  BH - current video page
  1310. ;------------------------------------------------------------------------------
  1311. clear_line    proc    near
  1312.         mov    cl,[si]            ;Get count
  1313.         xor    ch,ch
  1314.         jcxz    cline2            ;Exit if no characters
  1315.         push    cx            ;Save count
  1316.         call    home            ;Home the cursor
  1317.         mov    ah,3            ;Get cursor position
  1318.         int    10h
  1319.         pop    cx            ;Restore CX
  1320.         push    dx            ;Save cursor address
  1321.         mov    ah,2            ;Print ASCII spaces
  1322.         mov    dl,32
  1323. cline1:
  1324.         int    21h
  1325.         loop    cline1
  1326.         mov    ah,2            ;Home cursor again
  1327.         pop    dx
  1328.         int    10h
  1329.         mov    byte ptr [si],0        ;Reset count
  1330. cline2:
  1331.         ret
  1332. clear_line    endp
  1333.  
  1334. ;------------------------------------------------------------------------------
  1335. ; CMD_RECORD records the latest command in the command stack.
  1336. ; Entry:  DS:DX - input buffer address
  1337. ;------------------------------------------------------------------------------
  1338. cmd_record    proc    near
  1339.         mov    si,dx            ;Point SI to input buffer
  1340.         mov    al,[si+1]        ;Get length of input string
  1341.         cmp    al,cs:[minlength]    ;Is the length zero?
  1342.         jb    cmd_exit        ;Yes, then exit now
  1343.         inc    si            ;Advance SI to count byte
  1344.         push    cs            ;Point ES to command stack 
  1345.         pop    es            ;  segment
  1346.         mov    di,cs:[next_ptr]    ;Get command stack pointer
  1347.         mov    cl,7            ;Convert it to offset address
  1348.         shl    di,cl
  1349.         add    di,cs:[cmdstack_base]
  1350.         mov    cl,al            ;Transfer string length to CL
  1351.         inc    cl            ;Increment for count byte
  1352.         xor    ch,ch            ;Byte to word in CX
  1353.         cld                ;Clear DF
  1354.         rep    movsb            ;Copy string to command stack
  1355.         inc    cs:[next_ptr]        ;Update pointer
  1356.         mov    ax,cs:[cmdstack_size]
  1357.         cmp    cs:[next_ptr],ax    ;Wrap around if necessary
  1358.         jne    cmdrec1
  1359.         mov    cs:[next_ptr],0
  1360. cmdrec1:
  1361.         mov    cs:[cmd_ptr],0        ;Zero current command pointer
  1362. cmd_exit:
  1363.         ret
  1364. cmd_record    endp
  1365.  
  1366. ;------------------------------------------------------------------------------
  1367. ; SET_CURSOR sets the cursor mode based on the state of the insert flag.
  1368. ;------------------------------------------------------------------------------
  1369. set_cursor    proc    near
  1370.         cmp    cs:[insert_flag],0    ;Test state of insert flag
  1371.         je    setc1            ;Branch if not set
  1372.         mov    cx,cs:[cursor_mode]    ;Raise top by 2 scan lines
  1373.         sub    ch,2
  1374.         jns    setc2            ;Exit if it wraps around
  1375.         ret
  1376. setc1:
  1377.         mov    cx,cs:[cursor_mode]    ;Set default cursor
  1378. setc2:
  1379.         mov    ah,1            ;Set cursor mode
  1380.         int    10h
  1381.         ret
  1382. set_cursor    endp
  1383.  
  1384. ;============================================================================
  1385. ; MUXINT processes calls to interrupt 2Fh
  1386. ; Entry:  AH - Device ID
  1387. ; Exit:   AL - 0FFh if AH = Alias device ID. Unchanged otherwise.
  1388. ;         ES - Code segment if AH = Alias device ID. Unchanged otherwise.
  1389. ;============================================================================
  1390. muxint        proc    far
  1391.         assume    cs:code,ds:nothing,es:nothing
  1392.          cmp    ah,cs:[multiplex_id]    ;Check for program ID
  1393.         je    muxint_1        ;Its us, indicate installed.
  1394.         jmp    cs:[int2fh]             ;else pass the call on
  1395. muxint_1:
  1396.         mov    al,-1            ;Indicate Alias installed
  1397.         push    cs            ;ES = installed code segment
  1398.         pop    es
  1399.         iret
  1400. muxint        endp
  1401.  
  1402.         even                ;Align stack on word boundry
  1403. end_of_resident    =    $
  1404. ;----------------------------------------------------------------------------
  1405. ; Start of non-resident code.
  1406. ;----------------------------------------------------------------------------
  1407. final_install:
  1408.         rep    movsb            ;Copy alias list
  1409.         mov    di,cmdstack_base    ;Initialize command stack
  1410.         mov    cx,cmdstack_size    ;  area with leading zeroes
  1411.         jcxz    tsr            ;Branch if size is zero
  1412.         xor    al,al
  1413.         cld
  1414. final_loop:
  1415.         stosb
  1416.         add    di,127
  1417.         loop    final_loop
  1418. tsr:
  1419.         mov    ax,3100h        ;Terminate and stay resident
  1420.         int    21h
  1421.  
  1422. ;----------------------------------------------------------------------------
  1423. ; Non-resident data.
  1424. ;----------------------------------------------------------------------------
  1425. alrdy_installed    db    0            ;Installed flag
  1426. other_seg    dw    0            ;Segment of installed code
  1427. databuff_seg    dw    0            ;Segment of data buffer.
  1428.  
  1429. alias_buffer    dw    512            ;Extra buffer for alias list.
  1430. aliaslist_end    dw    0            ;Offset of end of the list.
  1431. alias_inlist    db    0            ;Flag used in alias list append
  1432.  
  1433. infomsg1    db    "ALIAS uninstalled$"
  1434. infomsg2    db    13,10,9,"Command stack size: $"
  1435. infomsg3    db    13,10,9,"Minimum stacked command length: $"
  1436. infomsg4    db    13,10,9,"Bytes free in alias buffer: $"
  1437. infomsg5    db    13,10,9,"Alias translation is $"
  1438. infomsg5d    db    "disabled",13,10,"$"
  1439. infomsg5e    db    "enabled",13,10,"$"
  1440. infomsg6    db    13,10,9,"FUNCTION KEY DEFINITIONS$"
  1441. infomsg7    db    13,10,9,"ALIAS DEFINITIONS$"
  1442. infomsg8    db    13,10,"For help type ALIAS ?$"
  1443. infomsg9    db    13,10,"Can",39,"t find Master Env. block$"
  1444.  
  1445. filemsg1    db    13,10,"Error in line $"    ;File identification message.
  1446. filemsg2    db    " of file: "
  1447. filenam_field    db    78 dup (0)        ;Name of current entry file.
  1448.  
  1449. errmsg0        db    "Need DOS 2.0 or greater$"
  1450. errmsg1        db    "ALIAS not installed$"
  1451.  
  1452. errmsg2        db    13,10,"Syntax: ALIAS [alias [command]] "
  1453.         db    "[/F filename] [/S nn] [/U]",13,10
  1454.         db    14 dup (" ")
  1455.         db    "[/B nn] [/D] [/E] [/L] [/M]",13,10,10
  1456.         db         9,"ALIAS alias command",13,10
  1457.         db         9,"ALIAS [fn] command",13,10,10
  1458.         db         9,"/B = Buffer size",13,10
  1459.         db         9,"/D = Disable alias translation",13,10
  1460.         db         9,"/E = Enable alias translation",13,10
  1461.         db         9,"/F = Filename of command file",13,10
  1462.         db         9,"/L = List aliases",13,10
  1463.         db         9,"/M = Minimum command length to stack",13,10
  1464.         db         9,"/S = Size of command stack",13,10
  1465.         db         9,"/U = Uninstall",13,10,"$"
  1466.  
  1467. errmsg3        db    "Can",39,"t uninstall$"
  1468. errmsg4        db    "Can",39,"t change parameter after installation$"
  1469. errmsg5        db    "Illegal number$"
  1470. errmsg6        db    "Can",39,"t find alias file$"
  1471. errmsg7        db    "Can",39,"t find COMMAND.COM$"
  1472. errmsg8        db    "Not enough memory$"
  1473. errmsg9        db    "Alias list full$"
  1474. errmsg10    db    "List and stack too large$"
  1475. errmsg11    db    "Invalid key assignment$"
  1476. errmsg12    db    "Number too big$"
  1477. errmsg13    db    "Alias not in list$"
  1478. errmsg14    db    "Error using Int 2Fh$"
  1479. endmsg        db    13,10,"$"
  1480.  
  1481. shiftmsg    db    "S-$"
  1482. altmsg        db    "A-$"
  1483. ctlmsg        db    "C-$"
  1484.  
  1485. file_linecount    dw    0            ;Line number being processed.
  1486. caps_flag    db    0
  1487. param_found    db    0            ;Cmd line parameter found flag
  1488. append_cr    db    0            ;Append cr to alias flag
  1489. cmdcom_name    db    "COMMAND"        ;Name of command.com
  1490.  
  1491. cmd_switches    db    "sfeldbum*/"        ;Letters of valid commands.
  1492. cmd_switch_end    =    $
  1493. cmd_jmp_tbl    dw    offset setstacksize    ;This jump table is used to
  1494.         dw    offset loadaliasfile    ;  call the routines that
  1495.         dw    offset enablealias      ;  process the command line
  1496.         dw    offset listalias    ;  arguments
  1497.         dw    offset disablealias
  1498.         dw    offset setlistbuffer
  1499.         dw    offset remove
  1500.         dw    offset minstacklen
  1501.         dw    offset comment_line    ;Comments can be indicated by
  1502.         dw    offset comment_line    ;  a /* or a //.
  1503.  
  1504. ;----------------------------------------------------------------------------
  1505. ; Initialization routine.
  1506. ;----------------------------------------------------------------------------
  1507. initialize    proc    near
  1508.         assume    cs:code,ds:code,es:code
  1509.         cld
  1510.         mov    ah,30h            ;Get DOS version
  1511.         int    21h
  1512.         xchg    al,ah            ;Swap major, minor numbers
  1513.         mov    dx,offset errmsg0    ;Bad DOS version
  1514.         cmp    ah,2            ;Run if DOS 2.0 or greater.
  1515.         jb     jmp_disp_error
  1516.         mov    dos_version,ax        ;Save version number
  1517.  
  1518.         mov    ax,max_code_size    ;Get size of installed code.
  1519.         mov    bx,ax
  1520.         shl    ax,1            ;Convert to bytes
  1521.         shl    ax,1
  1522.         shl    ax,1
  1523.         shl    ax,1
  1524.         mov    sp,ax            ;Move stack pointer
  1525.         sub    ax,512            ;Save room for stack
  1526.         mov    aliaslist_size,ax    ;Mark end of alias list
  1527.         mov    ah,4ah            ;Reduce memory allocation
  1528.          int    21h
  1529.  
  1530.         mov    bx,filebuf_size        ;Get size of file buffer,
  1531.          mov    ah,48h            ;Allocate memory block
  1532.          int    21h
  1533.          mov    dx,offset errmsg8    ;Not enough memory msg
  1534.          jc    jmp_disp_error
  1535.         mov    databuff_seg,ax        ;Save segment to file buffer.
  1536.  
  1537.         mov    ax,offset end_of_code            ;Initialize alias list
  1538.         mov    word ptr [aliaslist_ptr],ax    ;  pointers.
  1539.         mov    ax,cs
  1540.         mov    word ptr [aliaslist_ptr+2],ax
  1541.         les    di,aliaslist_ptr        ;Initialize alias list
  1542.         mov    ax,-1                ;  by writing a -1 as
  1543.         stosw                       ;  an end flag.
  1544.         mov    aliaslist_end,di
  1545. ;
  1546. ;See if a copy is already resident in memory. If > DOS 3.0, use int 2Fh.
  1547. ;
  1548.         mov    byte ptr [main+2],0    ;Initialize fingerprint
  1549.         cmp    dos_version,300h    ;See if DOS 3.0 or later
  1550.         jb    find_copy1        ;No, search the old way.
  1551.         mov    cx,16            ;Try 16 different IDs.
  1552. find_copy:
  1553.         xor    ax,ax
  1554.         mov    es,ax
  1555.         mov    ah,multiplex_id        ;Load ID.  Use Int 2Fh to
  1556.         int    2fh            ;  reach installed code so
  1557.         or    al,al            ;  that we are compatible
  1558.         jne    find_copy0        ;  with 386 memory managers.
  1559.         push    cs
  1560.         pop    es                      ;If AL not changed, ALIAS not
  1561.         jmp    short find_copy4    ;  installed.
  1562. find_copy0:
  1563.         push    cx
  1564.         call    cmpheader        ;See if really Alias by
  1565.         pop    cx                      ;  comparing file headers.
  1566.         je    find_copy3
  1567.         inc    multiplex_id        ;ID used by another program.
  1568.         loop    find_copy        ;  Change and try again.
  1569.         mov    dx,offset errmsg14    ;All IDs taken, print error
  1570. jmp_disp_error:
  1571.         jmp    disp_error            ;  msg and exit.
  1572. ;
  1573. ;For DOS 2.x find the installed code the old fashioned way by scanning
  1574. ;the memory control blocks.
  1575. ;
  1576. find_copy1:
  1577.         xor    bx,bx            ;zero BX for start
  1578.         mov    ax,cs            ;keep CS value in AX
  1579. find_copy2:
  1580.         inc    bx            ;increment search segment value
  1581.         mov    es,bx
  1582.         assume    es:nothing
  1583.         cmp    ax,bx            ;not installed if current
  1584.         je    find_copy4            ;  segment is found.
  1585.         call    cmpheader
  1586.         jne    find_copy2        ;loop back if not found
  1587. find_copy3:
  1588.         inc    alrdy_installed        ;Set installed flag
  1589. find_copy4:
  1590.         mov    other_seg,es        ;Save seg of installed code
  1591. ;
  1592. ;Copy the command line to the file buffer to treat as a one line file.
  1593. ;
  1594.         mov    ax,databuff_seg        ;Get segment of file buffer.
  1595.         mov    es,ax            ;Treat the command line as
  1596.         xor    di,di            ;  a 1 line file.
  1597.         mov    si,offset command_tail
  1598.         xor    cx,cx
  1599.         or    cl,[si]            ;Get command line length
  1600.         je    parse_line_end        ;If zero, skip parse routine
  1601.         inc    si                      ;Copy command line into file
  1602.         inc    cx            ;  buffer.
  1603.         push    cx
  1604.         rep    movsb
  1605.         pop    cx            ;CX = file size.
  1606.         xor    si,si            ;Point SI to start of buffer
  1607.         push    es
  1608.         pop    ds            ;Set DS to file buffer seg
  1609.         assume    ds:nothing
  1610.         mov    es,cs:[other_seg]     ;Set ES to installed code
  1611. ;
  1612. ;Parse command line and command files.
  1613. ;
  1614. parse_line_loop:
  1615.         xor    bl,bl
  1616.         call    scanline             ;Get 1st character
  1617.         jc    parse_2                 ;If carriage return, skip line
  1618.         cmp    al,"/"            ;Compare character to switch.
  1619.         je    parse_switch_found
  1620.         cmp    al,"?"            ;See if help character
  1621.         mov    dx,offset errmsg2    ;Command not found msg
  1622.         je    disp_error
  1623.         call    setkey              ;Must be alias definition
  1624.         jc    disp_error
  1625.         mov    param_found,1        ;Set parameter found flag
  1626.         jmp    short parse_2        ;Return to parse loop
  1627. parse_switch_found:
  1628.         mov    param_found,1        ;Set parameter found flag
  1629.         lodsb                ;Get command line switch
  1630.         dec    cx
  1631.         cmp    al,'A'             ;Convert to lower case if
  1632.         jb    parse_1            ;  necessary.
  1633.         cmp    al,'Z'
  1634.         ja    parse_1
  1635.         or    al,20h
  1636. parse_1:
  1637.         push    cx            ;Scan the list of allowable
  1638.         push    es            ;  command switches. If switch
  1639.         push    cs            ;  found, use its position for
  1640.         pop    es            ;  an index into the list of
  1641.         mov    di,offset cmd_switches    ;  routines.
  1642.         mov    cx,offset cmd_switch_end - offset cmd_switches
  1643.         mov    bx,offset cmd_switch_end - offset cmd_switches - 1
  1644.         repne    scasb
  1645.         mov    ax,cx            ;Copy index into list
  1646.         pop    es
  1647.         pop    cx
  1648.         mov    dx,offset errmsg2    ;Command not found msg
  1649.         jne    disp_error
  1650.         sub    bx,ax            ;Compute offset into list
  1651.         shl    bx,1            ;Convert to word offset
  1652.         add    bx,offset cmd_jmp_tbl    ;Add the start addr of table.
  1653.         call    cs:[bx]            ;Call command routine.
  1654.         jc    disp_error        ;If error terminate parse.
  1655. parse_2:
  1656.         jcxz    parse_line_end        ;If at file end, exit parse.
  1657.                 jmp    short parse_line_loop
  1658. ;
  1659. ;See if installed. If not, install.
  1660. ;
  1661. parse_line_end:
  1662.         cmp    cs:[param_found],1    ;See if any parameters found
  1663.         je     init2            ;If already installed and
  1664.         cmp    cs:[alrdy_installed],0    ;  no parameters on the
  1665.         je    init2            ;  command line, default to
  1666.         mov    es,cs:[other_seg]     ;  showing program information
  1667.         call    listalias
  1668. init2:
  1669.         mov    ah,49h            ;Release memory block used
  1670.         mov    es,cs:[databuff_seg]    ;  for file buffer.
  1671.         int    21h
  1672.         push    cs
  1673.         pop    ds
  1674.         assume    ds:code
  1675.         mov    word ptr databuff_seg,0    ;Indicate file buff released
  1676.         cmp    alrdy_installed,0    ;If not already installed,
  1677.         je    install            ;  jump to install routine.
  1678. exit:
  1679.         mov    ax,4C00h        ;Terminate with RC = 0
  1680.         int    21h
  1681. ;
  1682. ;Display error message.
  1683. ;
  1684.         assume    ds:nothing
  1685. disp_error:
  1686.         xor    ax,ax            ;If file buffer still
  1687.         or     ax,databuff_seg        ;  allocated, deallocate it.
  1688.         jz    disp_error0
  1689.         mov    ah,49h            ;Release memory block used
  1690.         mov     es,ax            ;  for file buffer.
  1691.         int    21h
  1692. disp_error0:
  1693.         push    cs
  1694.         pop    ds
  1695.         assume    ds:code
  1696.         cmp    byte ptr filenam_field,0
  1697.         je    disp_error1             ;If processing a file, print
  1698.         push    dx                      ;  a message informing the
  1699.         mov    dx,offset filemsg1      ;  user the filename being
  1700.         call    printmsg                ;  processed and the line
  1701.         mov    ax,file_linecount       ;  that the error occured.
  1702.         call    hex2asc
  1703.         mov    dx,offset filemsg2
  1704.         call    printmsgcr
  1705.         pop    dx
  1706. disp_error1:
  1707.         call    printmsgcr        ;print string
  1708.         mov    ax,4c01h        ;Terminate with RC = 1
  1709.         int    21h
  1710. ;
  1711. ;Install routine. Find segment of COMMAND.COM, hook into int 21h, 2Fh and TSR.
  1712. ;
  1713.         assume    ds:code
  1714. install:
  1715.         mov    dx,offset program       ;Display copyright message
  1716.         call    printmsg
  1717.  
  1718.         push    ds            ;Save DS
  1719.         xor    ax,ax            ;Then zero it
  1720.         mov    ds,ax
  1721.         mov    cs:[points],ax        ;Record number of scan lines
  1722.         mov    ax,ds:[0460h]        ;  per character and cursor
  1723.         mov    cs:[cursor_mode],ax    ;  mode
  1724.         pop    ds            ;Restore DS
  1725.  
  1726.         mov    byte ptr filenam_field,0  ;Don't callout file on error
  1727.         mov    ah,52h            ;get address of first MCB
  1728.         int    21h
  1729.         mov    ax,es:[bx-2]        ;point ES to MCB
  1730.         mov    cx,20            ;Allow only 20 loops.
  1731. mcb_loop:
  1732.         mov    es,ax
  1733.         cmp    byte ptr es:[0],"M"    ;check for mcb signature
  1734.         jne    mcb_error
  1735.         inc    ax            ;point AX to memory block
  1736.         cmp    ax,es:[1]        ;See if this is a PSP block
  1737.         je     psp_found
  1738. mcb_continue:
  1739.         add    ax,es:[3]        ;Get size of memory block
  1740.         loop    mcb_loop
  1741. mcb_error:
  1742.         mov    dx,offset errmsg7    ;Can't locate command.com PSP
  1743.         jmp    disp_error
  1744. psp_found:
  1745.         cmp    dos_version,0a00h    ;If OS/2, use DOS 3.3 method.
  1746.         jae    psp_found_1
  1747.         cmp     dos_version,0400h    ;If DOS 4.00 or greater,
  1748.         jb    psp_found_1        ;  COMMAND.COM may not be the
  1749.         push    ds            ;  first program loaded.  Look
  1750.         mov    si,offset cmdcom_name    ;  at the name of the program
  1751.         mov    di,8            ;  stored in the last 8 bytes
  1752.         mov    cx,7            ;  of the memory control
  1753.         repe    cmpsb            ;  block.  If the string
  1754.         pop    ds            ;  "COMMAND" isn't found, keep
  1755.         jne    mcb_continue        ;  looking.
  1756. psp_found_1:
  1757.         mov    cmdcom_psp,ax        ;Save segment of cmd.com PSP
  1758.         mov    es,ax
  1759.         mov    bx,es:[2ch]        ;Get seg of master environment
  1760.         mov    master_env,bx
  1761.         dec    bx
  1762.         mov    es,bx
  1763.         cmp    byte ptr es:[0],"M"    ;See if valid memory block
  1764.         je    psp_found_4
  1765.         mov    dx,ax            ;Save COMMAND PSP segment
  1766.         dec    ax               ;Point back to mcb
  1767.         mov    es,ax
  1768. psp_found_2:
  1769.         add    ax,es:[3]        ;Get size of memory block
  1770.         inc    ax
  1771.         cmp    es:[1],dx        ;See if owned by CMD.COM
  1772.         je    psp_found_3
  1773.         mov    es,ax
  1774.         loop    psp_found_2
  1775.         mov    dx,offset infomsg9    ;Indicate can't find env
  1776.         call    printmsgcr
  1777.         xor    ax,ax
  1778. psp_found_3:
  1779.         inc    ax
  1780.         mov    master_env,ax
  1781. psp_found_4:
  1782. ;
  1783. ;Set up pointers to the cmd stack and to move the alias list to the end of the
  1784. ;command stack so it takes up less space when ALIAS resident.
  1785. ;
  1786.         mov    di,mystack_ptr        ;Get base of internal stack
  1787.         mov    work_buff_ptr,di    ;Copy ptr to alias buffer
  1788.         add    di,128            ;Add size of buffer
  1789.         mov    cmdstack_base,di    ;Copy for start of cmd stack
  1790.         mov    ax,cmdstack_size    ;Get size of command stack
  1791.         mov    ah,128              ;128 bytes for each entry
  1792.         mul    ah
  1793.         add    di,ax                 ;Add to cmd stack for
  1794.         mov    si,word ptr aliaslist_ptr    ;  start of the
  1795.         mov    cx,aliaslist_end        ;  alias list.
  1796.         mov     word ptr aliaslist_ptr,di    ;Save new pointer.
  1797.         sub    cx,si               ;Compute size of list.
  1798.         mov    dx,di            ;See if we have enough room
  1799.         add    dx,cx            ;  for everything in one seg.
  1800.         jnc    install_1
  1801.         mov    dx,offset errmsg10    ;Not enough memory, exit.
  1802.         jmp    disp_error
  1803. install_1:
  1804.         add    dx,alias_buffer        ;Add additional space for list
  1805.         mov    aliaslist_size,dx    ;Save pointer to end of seg
  1806.         add    dx,15            ;Convert memory needed to
  1807.         shr    dx,1            ;  paragraphs.
  1808.         shr    dx,1
  1809.         shr    dx,1
  1810.         shr    dx,1
  1811.         cmp    di,si            ;Check for overlap in the move
  1812.         jb    install_2        ;If overlap, copy list from
  1813.         std                ;  the top down to avoid
  1814.         add    di,cx            ;  overwriting the list.
  1815.         add    si,cx
  1816.         dec    si
  1817.         dec    di
  1818. ;
  1819. ;Revector interrupts 21h and 2Fh (if necessary).
  1820. ;
  1821. install_2:
  1822.         mov    ax,3521h        ;Get interrupt 21 (DOS)
  1823.         int    21h                     ;  vector.
  1824.         mov    word ptr [int21h],bx
  1825.         mov    word ptr [int21h+2],es
  1826.         push    dx            ;Save memory size parameter
  1827.         mov    ax,2521h                ;Point int 21 to internal
  1828.         mov    dx,offset dosint        ;  routine.
  1829.         int    21h
  1830.  
  1831.         cmp    dos_version,300h    ;See if we are using Int 2Fh
  1832.         jb    install_3
  1833.         mov    ax,352fh        ;Get interrupt 2F (MUX)
  1834.         int    21h                     ;  vector.
  1835.         mov    word ptr [int2fh],bx
  1836.         mov    word ptr [int2fh+2],es
  1837.         mov    ax,252fh                ;Point int 2F to internal
  1838.         mov    dx,offset muxint        ;  routine.
  1839.         int    21h
  1840. install_3:
  1841.         pop    dx
  1842.         push    ds            ;ES = DS
  1843.         pop    es
  1844.                 jmp    final_install        ;Jump to safe place for move.
  1845. initialize    endp
  1846.  
  1847. ;-----------------------------------------------------------------------------
  1848. ; CMPHEADER compares the first 16 bytes of this file with the segment
  1849. ;           pointed to by ES.
  1850. ; Entry:  DS - code segment
  1851. ;         ES - pointer to segment to compare
  1852. ; Exit:   ZF - 0 = segments match.
  1853. ;-----------------------------------------------------------------------------
  1854. cmpheader    proc    near
  1855.         mov    si,offset main+2    ;Search this segment for ASCII
  1856.         mov    di,si            ;  fingerprint.
  1857.         mov    cx,16
  1858.         repe    cmpsb
  1859.         ret
  1860. cmpheader    endp
  1861.  
  1862. ;-----------------------------------------------------------------------------
  1863. ; PRINTMSG prints the message pointed to by DX to the screen.
  1864. ; Entry:  DX - pointer to ASCII message terminated by $
  1865. ;-----------------------------------------------------------------------------
  1866. printmsg    proc    near
  1867.         assume    ds:nothing,es:nothing
  1868.         push    ds
  1869.         push    cs
  1870.         pop    ds
  1871.         assume    ds:code
  1872.         mov    ah,9            ;Print message
  1873.         int    21h
  1874.         pop    ds
  1875.         ret
  1876. printmsg    endp
  1877.  
  1878. ;-----------------------------------------------------------------------------
  1879. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  1880. ; Entry:  DX - pointer to ASCII message terminated by $
  1881. ;-----------------------------------------------------------------------------
  1882. printmsgcr    proc    near
  1883.         assume    ds:nothing,es:nothing
  1884.         push    dx
  1885.         call    printmsg
  1886.         mov    dx,offset endmsg
  1887.         call    printmsg
  1888.         pop    dx
  1889.         ret
  1890. printmsgcr    endp
  1891.  
  1892. ;-----------------------------------------------------------------------------
  1893. ; SETSTACKSIZE - Sets the size of the command line stack.
  1894. ; Entry:  DS:SI - points to stack size in ascii
  1895. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  1896. ;-----------------------------------------------------------------------------
  1897. setstacksize    proc    near
  1898.         assume    ds:nothing,es:nothing
  1899.         xor    bl,bl            ;Check for installed code
  1900.         call    setparameter        ;Get num and convert to binary
  1901.         jc    setstack_exit        ;Check for error
  1902.         mov    cs:[cmdstack_size],ax    ;Save parameter
  1903. setstack_exit:
  1904.         ret
  1905. setstacksize    endp
  1906.  
  1907. ;-----------------------------------------------------------------------------
  1908. ; SETLISTBUFFER - Sets the size of the additional buffer reserved for alias
  1909. ;                 list expansion.
  1910. ; Entry:  DS:SI - points to buffer size in ascii
  1911. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  1912. ;-----------------------------------------------------------------------------
  1913. setlistbuffer    proc    near
  1914.         assume    ds:nothing,es:nothing
  1915.         xor    bl,bl            ;Check for installed code
  1916.         call    setparameter        ;Get num and convert to binary
  1917.         jc    setlistbuffer_exit      ;Check for error
  1918.         mov    cs:[alias_buffer],ax    ;Save buffer size parameter
  1919. setlistbuffer_exit:
  1920.         ret
  1921. setlistbuffer    endp
  1922.  
  1923. ;-----------------------------------------------------------------------------
  1924. ; MINSTACKLEN - sets the minimum legth of a command to stack.
  1925. ; Entry:     ES - segment of the installed code
  1926. ;         DS:SI - points to buffer size in ascii
  1927. ; Exit:      CF - Clear if sucessful, Set if error, DX points to error msg.
  1928. ;-----------------------------------------------------------------------------
  1929. minstacklen    proc    near
  1930.         assume    ds:nothing,es:nothing
  1931.         mov    bl,1             ;Don't check for installed code
  1932.         call    asc2bin            ;Get num and convert to binary
  1933.         jc    minstacklen_exit    ;Check for error
  1934.         cmp    al,126
  1935.         jb    minstacklen_1
  1936.         mov    dx,offset errmsg12    ;Stack length too big
  1937.         stc
  1938.         jmp    short minstacklen_exit
  1939. minstacklen_1:
  1940.         or     al,al            ;Make sure min length is not
  1941.         jne    minstacklen_2        ; specified at 0. If so,
  1942.         inc    al            ; change to 1.
  1943. minstacklen_2:
  1944.         mov    es:[minlength],al    ;Save minimum length parameter
  1945. minstacklen_exit:
  1946.         ret
  1947. minstacklen    endp
  1948.  
  1949. ;-----------------------------------------------------------------------------
  1950. ; SETPARAMETER - Common code used by the set stack and set buffer and set
  1951. ;                minimum command length routines.
  1952. ; Entry:  DS:SI - points to ascii number
  1953. ;            BL - Flag to indicate check for installed code, BL=0, check.
  1954. ; Exit:      CF - Clear if sucessful, Set if error.
  1955. ;-----------------------------------------------------------------------------
  1956. setparameter    proc    near
  1957.         assume    ds:nothing,es:nothing
  1958.         mov    dx,offset errmsg4     ;Can't change parameter msg
  1959.         cmp    cs:[alrdy_installed],1    ;If already installed don't
  1960.         je     setparam_error          ;  change parameter.
  1961.         call    asc2bin
  1962. setparam_exit:
  1963.         ret
  1964. setparam_error:
  1965.         stc                ;Set error flag.
  1966.         jmp    short setparam_exit
  1967. setparameter    endp
  1968.  
  1969. ;-----------------------------------------------------------------------------
  1970. ; SETKEY modifies the alias list to add function key definitions.
  1971. ; Entry:  DS:SI - pointer to string identifing the function key
  1972. ;            ES - pointer to segment of installed code
  1973. ; Exit:      CF - clear if successful
  1974. ;-----------------------------------------------------------------------------
  1975. setkey        proc    near
  1976.         assume    ds:nothing,es:nothing
  1977.         push    es
  1978.         cmp    al,"["            ;Determine alias or key
  1979.         je    setkey_1
  1980.          dec    si                      ;Backup before last key
  1981.          inc    cx
  1982.         jmp    short setkey_5
  1983. setkey_1:
  1984.         lodsb                ;Get next character
  1985.         dec    cx
  1986.         jcxz     setkey_badkey
  1987.         mov    bx,58            ;Load default F1 keycode
  1988.         or    al,20h            ;Convert to lower case
  1989.         cmp    al,"f"
  1990.         je    setkey_3
  1991.         add    bx,25            ;Assume shift F1 keycode
  1992.         cmp    al,"s"
  1993.         je    setkey_2
  1994.         add    bx,10            ;Assume ctl F1 keycode
  1995.         cmp    al,"c"
  1996.         je    setkey_2
  1997.         add    bx,10            ;Assume alt F1 keycode
  1998.         cmp    al,"a"
  1999.         jne    setkey_badkey
  2000. setkey_2:
  2001.         lodsb                ;Get next character
  2002.         dec    cx
  2003.         or    al,20h            ;Convert to lower case
  2004.         cmp    al,"f"            ;Make sure next key is "f"
  2005.         jne    setkey_badkey
  2006. setkey_3:
  2007.         call    asc2bin
  2008.         jc      setkey_badkey        ;If bad number, exit
  2009.         or     ax,ax
  2010.         je    setkey_badkey        ;Make sure not zero
  2011.         cmp    ax,10
  2012.         ja    setkey_badkey        ;Make sure less than 10
  2013.         cmp    byte ptr [si-1],"]"    ;Check for closing bracket
  2014.         jne     setkey_badkey        ;  if not found, error
  2015.         add    bx,ax            ;Add in function key number
  2016.         cmp    byte ptr [si]," "       ;Check to see if a character
  2017.         jbe    setkey_4                ;  trails the closing bracket.
  2018.         cmp    byte ptr [si],"*"       ;Check to see if an * is
  2019.         jne    setkey_badkey        ;  appended to the function
  2020.         lodsb                           ;  key assignment. If so,
  2021.         dec    cx                      ;  remove key and set flag
  2022.         mov    cs:[append_cr],1        ;  to append cr to command.
  2023. setkey_4:
  2024.         sub    si,2            ;Back up to keycode.
  2025.         xor    bh,bh
  2026.         mov    ds:[si],bx        ;Save keycode on command line
  2027.         add    cx,2
  2028. setkey_5:
  2029.         call    setalias                ;Use SETALIAS to load
  2030. setkey_exit:
  2031.         pop    es            ;Restore ptr to installed seg
  2032.         ret
  2033. setkey_badkey:
  2034.         mov    dx,offset errmsg11    ;Bad key assignment msg
  2035.         stc
  2036.         jmp    setkey_exit
  2037. setkey        endp
  2038.  
  2039. ;-----------------------------------------------------------------------------
  2040. ; SETALIAS modifies the alias list according to command line agruments.
  2041. ; Entry:  DS:SI - pointer to string to be inserted into alias list.
  2042. ;            ES - pointer to segment of installed code.
  2043. ; Exit:      CF - clear if successful
  2044. ;-----------------------------------------------------------------------------
  2045. setalias    proc    near
  2046.         assume    ds:nothing,es:nothing
  2047.         push    es
  2048.         xor    bl,bl            ;Find 1st character on
  2049.         call    scanline        ;  command line.
  2050.         jnc    setalias_1        ;If at end of line, exit
  2051.         jmp    setalias_exit        ;  routine.
  2052. setalias_1:
  2053. ;
  2054. ;Get length of alias, then search list for matching alias
  2055. ;
  2056.          dec    si            ;Backup to before 1st char.
  2057.         inc    cx
  2058.         mov    byte ptr cs:[alias_inlist],0 ;Assume not in list
  2059.         call    searchalias        ;Is there already an alias?
  2060.         jc     setalias_2        ;No, continue.
  2061.  
  2062.         inc    byte ptr cs:[alias_inlist]
  2063.         call    delete_aliasent        ;Delete entry from list
  2064. setalias_2:
  2065. ;
  2066. ;Append new alias to the end of the list.
  2067. ;
  2068.         mov     bp,di            ;Save ptr to end of list.
  2069.         add    di,4                    ;Move past length fields.
  2070.         push    es            ;Get max size of alias list.
  2071.         mov    es,cs:[other_seg]
  2072.         mov    dx,es:[aliaslist_size]
  2073.         pop    es
  2074. ;
  2075. ;Append alias to list.
  2076. ;
  2077.         xor    ax,ax            ;Clear character counter
  2078. setalias_3:
  2079.         lodsb                ;Get byte
  2080.         dec    cx            ;Decriment buffer counter.
  2081.         jcxz    setalias_4             ;If at end of file, exit.
  2082.         cmp    al,13             ;See if at end of line.
  2083.         jne    setalias_6             ;No, continue.
  2084. setalias_4:
  2085.         cmp    byte ptr cs:[alias_inlist],0
  2086.         jne    setalias_5            ;Was alias in list?
  2087.         jmp    setalias_notnfil    ;No, incomplete alias specifed
  2088. setalias_5:
  2089.         jmp    setalias_exit        ;Yes, alias simply erased.
  2090. setalias_6:
  2091.         cmp    al,' '            ;See if at end of tag.
  2092.         je    setalias_8        ;Yes, exit copy loop
  2093.         cmp    al,9            ;Check for tab
  2094.         je    setalias_8
  2095.         cmp    di,dx             ;See if alias list is full
  2096.         jbe    setalias_7          ;No, continue
  2097.         jmp    setalias_full        ;Yes, exit routine
  2098. setalias_7:
  2099.         stosb                ;No, add character to list
  2100.         inc    ah               ;Inc size of tag
  2101.         jmp    short setalias_3
  2102. setalias_8:
  2103.         mov    es:[bp+2],ah        ;Save size of alias
  2104. ;
  2105. ;Append command to alias list.
  2106. ;
  2107.         mov    cs:[caps_flag],0    ;Initialize setcaps flag.
  2108.         xor    bx,bx            ;Find 1st character in
  2109.         call    scanline        ;  command.
  2110.         jc    setalias_exit        ;If no command, exit
  2111.         xor    ah,ah            ;Clear character counter
  2112. setalias_9:
  2113.         cmp    al,"%"            ;Check for environment var
  2114.         jne    setalias_11        ;  by checking for % signs.
  2115.         cmp    cs:[caps_flag],0    ;If caps flag set capitialize
  2116.         jne    setalias_10        ;  string before saving.
  2117.         mov    bl,ds:[si]        ;Get next character
  2118.         cmp    bl,"0"            ;If numeric, assume this is
  2119.         jb    setalias_10        ;  a line parameter, not an
  2120.         cmp    bl,"9"            ;  environment variable so
  2121.         jbe    setalias_11        ;  don't set caps flag.
  2122.         cmp    bl,"%"            ;Don't let double % signs
  2123.         je    setalias_11        ;  indicate environment var.
  2124. setalias_10:
  2125.         not    byte ptr cs:[caps_flag]    ;Toggle caps flag
  2126. setalias_11:
  2127.         cmp    cs:[caps_flag],0    ;Capitialize environment
  2128.         je    setalias_12        ;  variables so they will
  2129.         cmp    al,"a"            ;  match when searched for in
  2130.         jb     setalias_12        ;  the environment block.
  2131.         cmp    al,"z"
  2132.         ja     setalias_12
  2133.         and    al,0dfh            ;Make character uppercase.
  2134. setalias_12:
  2135.         cmp    di,dx             ;See if alias list is full
  2136.         ja     setalias_full        ;Yes, exit routine
  2137.         stosb                ;Append character on list
  2138.         inc    ah               ;Inc character counter.
  2139.         jcxz    setalias_13        ;Check for end of file.
  2140.         lodsb                ;Get next character
  2141.         dec    cx            ;Dec file counter.
  2142.         cmp    al,13            ;See if carriage return.
  2143.         jne    setalias_9              ;If not continue
  2144. setalias_13:
  2145.         cmp    cs:[append_cr],1    ;If flag set, append carrage
  2146.         jne    setalias_14        ;  return to command.
  2147.         mov    al,13
  2148.         inc    ah
  2149.         stosb
  2150.         mov    cs:[append_cr],0    ;Clear flag
  2151. setalias_14:
  2152.         mov    es:[bp+3],ah        ;Save command size
  2153.         mov    word ptr es:[di],-1    ;Set new end of list flag
  2154.         mov    ax,di                  ;Save end pointer to list
  2155.         add    ax,2            ;Make room for the end flag.
  2156.         mov    cs:[aliaslist_end],ax
  2157.         sub    di,bp            ;Compute size of entry
  2158.         mov    es:[bp],di        ;Put size over old end flag.
  2159.         inc    cs:[file_linecount]    ;Point counter to next line.
  2160. setalias_exit:
  2161.         clc
  2162. setalias_exit1:
  2163.         pop    es            ;Restore ptr to installed seg
  2164.         ret
  2165. setalias_full:
  2166.         mov    dx,offset errmsg9    ;Alias list too large msg.
  2167.         stc
  2168.         jmp    short setalias_exit1
  2169. setalias_notnfil:
  2170.         mov    dx,offset errmsg13    ;Alias not in list.
  2171.         stc
  2172.         jmp    short setalias_exit1
  2173. setalias    endp
  2174.  
  2175. ;-----------------------------------------------------------------------------
  2176. ; DELALIASENTRY - Deletes an alias entry
  2177. ; Entry:  DS:SI - pointer to the entry in the alias list to delete
  2178. ; Exit:      CF - clear if successful
  2179. ;-----------------------------------------------------------------------------
  2180. delete_aliasent    proc    near
  2181.         push    cx            ;Save registers
  2182.         push    si
  2183.         push    ds                      ;Yes, remove entry from list
  2184.         push    es                      ;  by moving the remainder of
  2185.         pop     ds                      ;  the list over this entry.
  2186.         mov    si,es:[di]        ;Point SI to the next list
  2187.         add    si,di            ;  entry.
  2188. delent_1:
  2189.         cmp     word ptr es:[si],-1       ;Check for the end of the list
  2190.         je    delent_2
  2191.         mov    cx,es:[si]        ;Get size of entry
  2192.         rep    movsb            ;Copy next entry over current
  2193.         jmp    short delent_1        ;  entry.
  2194. delent_2:
  2195.         mov    word ptr es:[di],-1    ;Set end of list indicator
  2196.         pop    ds            ;Get back file buffer pointer
  2197.         pop    si
  2198.         pop    cx
  2199.         ret
  2200. delete_aliasent    endp
  2201.  
  2202. ;-----------------------------------------------------------------------------
  2203. ; LOADALIASFILE loads a file containing a list of alias commands.
  2204. ; Entry:  DS:SI - pointer to the name of the file to open
  2205. ; exit:      CX - size of the file in bytes
  2206. ;            CF - clear if successful
  2207. ;-----------------------------------------------------------------------------
  2208. loadaliasfile    proc    near
  2209.         assume    ds:nothing,es:nothing
  2210.         xor    bl,bl
  2211.         call    scanline        ;Find 1st char of filename.
  2212.         mov     dx,si            ;Copy filename pointer
  2213.         inc    bl            ;Find end of filename
  2214.         call    scanline
  2215.         mov    byte ptr [si-1],0    ;Make filename ASCIIZ.
  2216.         dec    dx
  2217.         mov    ax,3d00h        ;Open file (Read only)
  2218.         int    21h
  2219.         jc    loadfile_error
  2220.         mov    bx,ax            ;Copy file handle
  2221. ;
  2222. ;Save the name of the file for error messages.
  2223. ;
  2224.         push    si
  2225.         push    es
  2226.         mov    di,offset filenam_field
  2227.         push    cs
  2228.         pop    es
  2229.         mov    si,dx
  2230. loadfile_1:
  2231.         lodsb
  2232.         stosb
  2233.         or    al,al
  2234.         jne    loadfile_1
  2235.         mov    byte ptr es:[di-1],"$"    ;Terminate string with $.
  2236.         pop    es
  2237.         pop    si
  2238. ;
  2239. ;Open file and read contents into file buffer.
  2240. ;
  2241.         mov    ah,3fh            ;Read alias file
  2242.         xor    dx,dx            ;Point to base of file buffer.
  2243.         mov    cx,cs:[filebuf_size]    ;Get size of file buffer.
  2244.         shl    cx,1            ;Convert to bytes
  2245.         shl    cx,1
  2246.         shl    cx,1
  2247.         shl    cx,1
  2248.          int    21h
  2249.         mov    si,ax
  2250.         mov    byte ptr ds:[si],13    ;Append a CR to end of file.
  2251.         mov     cx,ax            ;Save new file size
  2252.         xor    si,si            ;Reset file pointer.
  2253.         mov    ah,3eh            ;Close file.
  2254.         int    21h
  2255.         mov    cs:[file_linecount],1    ;Reset line counter.
  2256. loadfile_exit:
  2257.         clc
  2258. loadfile_exit1:
  2259.         ret
  2260. loadfile_error:
  2261.         stc
  2262.         mov    dx,offset errmsg6    ;Bad filename specified.
  2263.         jmp    short loadfile_exit1
  2264. loadaliasfile    endp
  2265.  
  2266. ;-----------------------------------------------------------------------------
  2267. ; LISTALIAS prints the alias list to screen.
  2268. ; Entry:  ES - segment of the installed code
  2269. ;-----------------------------------------------------------------------------
  2270. listalias    proc    near
  2271.         assume    ds:nothing,es:nothing
  2272.         push    ds
  2273. ;
  2274. ;Print Command stack size and amount of alias buffer space remaining
  2275. ;
  2276.         mov    dx,offset infomsg2    ;Print size of command stack
  2277.         call    printmsg
  2278.         mov    ax,es:[cmdstack_size]    ;Get size of command stack
  2279.         call    hex2asc            ;Print size
  2280.         mov    dx,offset infomsg3    ;Print min cmd length
  2281.         call    printmsg
  2282.         xor    ax,ax
  2283.         mov    al,es:[minlength]    ;Get min cmd length to stack
  2284.         call    hex2asc            ;Print length
  2285.         mov    dx,offset infomsg4    ;Print label to buffer size
  2286.         call    printmsg
  2287.         lds    si,es:[aliaslist_ptr]    ;Get pointer to alias list
  2288. listalias_1:
  2289.         cmp    word ptr [si],-1    ;Scan through alias list to
  2290.         je    listalias_2        ;  find the end of the list.
  2291.                 add    si,[si]            ;Point to next entry
  2292.         jmp    short listalias_1
  2293. listalias_2:
  2294.         mov    ax,es:[aliaslist_size]    ;Get offset to end of buffer
  2295.         sub    ax,si            ;Subtract end of alias list
  2296.         sub    ax,2            ;Correct for end pointer
  2297.         call    hex2asc            ;Print size
  2298.         mov    dx,offset infomsg5    ;Indicate if alias translation
  2299.         call    printmsg        ;  is enabled or disabled
  2300.         mov    dx,offset infomsg5d    ;Disabled message
  2301.         cmp    byte ptr es:[chk_alias],0    ;See if alias enabled
  2302.         je    listalias_3
  2303.         mov    dx,offset infomsg5e     ;Enabled message
  2304. listalias_3:
  2305.         call    printmsg
  2306. ;
  2307. ;Scan through alias list to print function key assignments
  2308. ;
  2309.         xor    dx,dx            ;Clear alias found flag
  2310.         lds    si,es:[aliaslist_ptr]    ;Get pointer to alias list
  2311. listalias_4:
  2312.         cmp    word ptr [si],-1    ;Check for end of list
  2313.         jne    listalias_5
  2314.         jmp    listalias_11
  2315. listalias_5:
  2316.         mov    bx,si            ;Save pointer to entry.
  2317.          cmp    byte ptr [si+5],0    ;See if key assignment
  2318.          je    listalias_6        ;If so, skip entry
  2319.         or      dh,1            ;Set alias found flag
  2320.         add    si,[bx]            ;Point to next entry
  2321.         jmp    short listalias_4
  2322. listalias_6:
  2323. ;
  2324. ;Convert scan code into function key label
  2325. ;
  2326.         test    dh,80h            ;See if first time though
  2327.         jne    listalias_7
  2328.         push    dx
  2329.         mov    dx,offset infomsg6      ;If first time print header
  2330.         call    printmsgcr
  2331.         pop    dx
  2332.         or    dh,80h            ;Set header printed flag
  2333. listalias_7:
  2334.         call    printtab
  2335.         push    dx
  2336.                 add    si,4             ;Point SI to command string
  2337.         mov    al,[si]            ;Get key code
  2338.         mov    dh,al
  2339.         cmp    al,84                   ;Check for base code
  2340.         jb     listalias_9
  2341.         sub    dh,25
  2342.         mov     di,offset shiftmsg    ;Assume shift prefix
  2343.         cmp    al,94            ;Check for shift
  2344.         jb    listalias_8
  2345.         sub    dh,10
  2346.         mov     di,offset ctlmsg    ;Assume control prefix
  2347.         cmp    al,104            ;Check for ctl
  2348.         jb    listalias_8
  2349.         mov     di,offset altmsg    ;Assume alt prefix
  2350.         sub    dh,10
  2351. listalias_8:
  2352.         push    dx            ;Print prefix identifier
  2353.         mov    dx,di
  2354.         call    printmsg
  2355.         pop    dx
  2356. listalias_9:
  2357.         mov    dl,"F"            ;Set function key
  2358.         mov    ah,2            ;Character output
  2359.         int    21h
  2360.         mov    al,dh              ;Get modified key code
  2361.         sub    al,58            ;Convert from scan code to hex
  2362.         xor    ah,ah
  2363.         call    hex2asc            ;Print function key number
  2364.         mov    cl,[bx+3]        ;Get length of command
  2365.         inc    si            ;Point SI to command string
  2366.         inc    si
  2367.         mov    di,bx
  2368.         add    di,[bx]
  2369.         cmp    byte ptr [di-1],13    ;Check for carrage return
  2370.         jne    listalias_10        ;  after command. If found,
  2371.         mov    dl,'*'            ;  indicate immediate command
  2372.         mov    ah,2            ;  by appending an * to the
  2373.         int    21h            ;  end of the function key.
  2374. listalias_10:
  2375.         call    printtab
  2376.         call    printtab
  2377.         call    print_string        ;Print command to screen
  2378.         mov    dx,offset endmsg    ;Append carriage return to
  2379.         call    printmsg        ;  advance to next line. SI
  2380.         pop    dx                      ;  points to the next entry.
  2381.         jmp    listalias_4
  2382. ;
  2383. ;Scan through alias list to print aliases.
  2384. ;
  2385. listalias_11:
  2386.          test    dh,1                  ;See if any aliases found
  2387.          je    listalias_exit        ;If no aliases, skip remainder
  2388.         mov    dx,offset infomsg7    ;Print header
  2389.         call    printmsgcr
  2390.         xor    cx,cx            ;Clear CX
  2391.         lds    si,es:[aliaslist_ptr]    ;Get pointer to alias list
  2392. listalias_12:
  2393.         mov    bx,si            ;Save pointer to entry.
  2394.          cmp    byte ptr [si+5],0    ;See if key definition
  2395.          jne    listalias_13        ;If so, skip entry
  2396.         add    si,[bx]
  2397.         jmp    short listalias_14
  2398. listalias_13:
  2399.         call    printtab
  2400.                 add    si,4             ;Point SI to alias string
  2401.         mov    cl,[bx+2]        ;Get length of alias
  2402.         call    print_string        ;Print alias to screen
  2403.         call    printtab
  2404.         call    printtab
  2405.         mov    cl,[bx+3]        ;Get length of command
  2406.         call    print_string        ;Print command to screen
  2407.         mov    dx,offset endmsg    ;Append carriage return to
  2408.         call    printmsg        ;  advance to next line.
  2409. listalias_14:
  2410.         cmp    word ptr [si],-1    ;Check for end of list. SI
  2411.         jne    listalias_12        ;  points to the next entry.
  2412. listalias_exit:
  2413.         mov    dx,offset infomsg8    ;Print pointer to help msg
  2414.         call    printmsgcr
  2415.         pop    ds
  2416.         clc
  2417.         ret
  2418. listalias    endp
  2419.  
  2420. ;-----------------------------------------------------------------------------
  2421. ; PRINTTAB prints a TAB character to the screen.
  2422. ; Entry:  ES - segment of the installed code
  2423. ;-----------------------------------------------------------------------------
  2424. printtab    proc    near
  2425.         assume    ds:nothing,es:nothing
  2426.         mov    ah,2            ;Character output
  2427.         mov    dl,9            ;Print TAB character
  2428.         int    21h
  2429.         ret
  2430. printtab    endp
  2431.  
  2432. ;-----------------------------------------------------------------------------
  2433. ; ENABLEALIAS enables alias translation.
  2434. ; Entry:  ES - segment of the installed code
  2435. ;-----------------------------------------------------------------------------
  2436. enablealias    proc    near
  2437.         assume    ds:nothing,es:nothing
  2438.         mov    byte ptr es:[chk_alias],1    ;Enable alias
  2439.         clc
  2440.         ret
  2441. enablealias    endp
  2442.  
  2443. ;-----------------------------------------------------------------------------
  2444. ; DISABLEALIAS disables alias translation.
  2445. ; Entry:  ES - segment of the installed code
  2446. ;-----------------------------------------------------------------------------
  2447. disablealias     proc    near
  2448.         assume    ds:nothing,es:nothing
  2449.         mov    byte ptr es:[chk_alias],0    ;Disable alias
  2450.         clc
  2451.         ret
  2452. disablealias     endp
  2453.  
  2454. ;-----------------------------------------------------------------------------
  2455. ; REMOVE uninstalls the installed program from memory.
  2456. ;-----------------------------------------------------------------------------
  2457. remove        proc    near
  2458.         assume    ds:nothing,es:nothing
  2459.         push    ds
  2460.         mov    dx,offset errmsg1    ;Not installed msg
  2461.         cmp    cs:[alrdy_installed],0    ;See if installed
  2462.         je     remove_exit           ;Not installed, error
  2463.  
  2464.         mov    cx,cs:[other_seg]    ;Get segment of installed code
  2465.         mov    ax,3521h                ;Get DOS vector
  2466.         int    21h
  2467.         mov    ax,es            ;Check to make sure DOS
  2468.         cmp    ax,cs:[other_seg]    ;  vector not modified.
  2469.         jne    remove_error
  2470.  
  2471.         lds    dx,es:[int2fh]        ;Get old interrupt 2F vector
  2472.         cmp    dx,-1            ;See if Int used
  2473.         je    remove_1        ;No, skip check of Int 2F
  2474.         mov    ax,352fh                ;Get MUX vector
  2475.         int    21h
  2476.         mov    ax,es            ;Check to make sure MUX
  2477.         cmp    ax,cs:[other_seg]    ;  vector not modified.
  2478.         jne    remove_error
  2479.         mov    ax,252fh        ;Set interrupt
  2480.         int    21h
  2481. remove_1:
  2482.         lds    dx,es:[int21h]        ;Get old interrupt 21 vector
  2483.         mov    ax,2521h        ;Set interrupt
  2484.         int    21h
  2485.         mov    cx,es:[env_segment]
  2486.         mov    ah,49h            ;Free memory block
  2487.         int    21h
  2488.         mov    es,cx            ;Free environment block
  2489.         mov    ah,49h
  2490.         int    21h
  2491.         mov    dx,offset infomsg1    ;Indicate uninstalled.
  2492.         mov    byte ptr filenam_field,0 ;Clear filename field
  2493. remove_exit:
  2494.         stc
  2495.         pop    ds
  2496. remove_exit1:    ret
  2497. remove_error:
  2498.                  mov    dx,offset errmsg3    ;Can't remove error msg
  2499.         jmp    short remove_exit
  2500.  
  2501. remove        endp
  2502.  
  2503. ;-----------------------------------------------------------------------------
  2504. ; COMMENT_LINE allows comments in the alias file by skipping to the next
  2505. ; carriage return.
  2506. ; Entry:  SI - pointer to ASCII string
  2507. ;         CX - file length
  2508. ;-----------------------------------------------------------------------------
  2509. comment_line    proc near
  2510.         assume    ds:nothing,es:nothing
  2511. comment_loop:
  2512.         push    es
  2513.         push    ds
  2514.         pop    es
  2515.         mov    di,si            ;Copy file pointer
  2516.         mov    al,13            ;Scan for carriage return.
  2517.         repne    scasb
  2518.         inc    cs:[file_linecount]    ;Inc file line counter.
  2519.         mov    si,di            ;Restore file pointer.
  2520.         pop    es
  2521.         clc
  2522.          ret
  2523. comment_line    endp
  2524.  
  2525. ;-----------------------------------------------------------------------------
  2526. ; HEX2ASC converts a binary number to ASCII and prints it to the screen.
  2527. ; Entry:  AX - binary number
  2528. ;-----------------------------------------------------------------------------
  2529. hex2asc        proc near
  2530.         assume    ds:nothing,es:nothing
  2531.         push    bx
  2532.         mov    cx,5            ;Allow max of five digits
  2533. hex_loop1:
  2534.         xor    dx,dx                   ;Clear high word
  2535.         mov    bx,10            ;Load number base
  2536.         div    bx            ;Divide by base (10)
  2537.         add    dl,30h              ;Convert to ascii
  2538.         push    dx                      ;Save digit on stack
  2539.         loop    hex_loop1
  2540.         mov    cx,5            ;Allow max of five digits
  2541.         mov    bl,"0"            ;Set leading zero indicator
  2542. hex_loop2:
  2543.         pop    dx            ;Get digit off stack
  2544.         or     bl,dl             ;Don't print leading zeros.
  2545.         cmp    bl,"0"            ;The first non zero will
  2546.         je    hex_1            ;  change bl to non-zero.
  2547.         mov    ah,2            ;DOS character output
  2548.         int    21h
  2549. hex_1:
  2550.         loop    hex_loop2
  2551. hex_exit:
  2552.         pop    bx
  2553.          ret
  2554. hex2asc         endp
  2555.  
  2556. ;-----------------------------------------------------------------------------
  2557. ; ASC2BIN - converts an ASCII number of the command line to hex.
  2558. ; Entry:  DS:SI - pointer to ASCII number
  2559. ;-----------------------------------------------------------------------------
  2560. asc2bin        proc    near
  2561.         push    bx
  2562.         xor    bl,bl
  2563.         call    scanline        ;Find next character.
  2564.         mov    di,offset errmsg5    ;Bad number message
  2565.         jc    asc_error        ;If no number found, error
  2566.         mov    bl,al            ;Copy first digit.
  2567.                 xor    ax,ax            ;Clear out sum
  2568.         xor    bh,bh            ;Clear high byte for word adds
  2569. asc_loop:
  2570.         cmp    bl," "          ;If space, assume end of
  2571.         jbe    asc_exit        ;  number.
  2572.         cmp    bl,"]"            ;Exit if closing bracket
  2573.         je    asc_exit        ;  encountered
  2574.         sub    bl,"0"            ;Check for valid number then
  2575.         jb    asc_error        ;  convert to binary.
  2576.         cmp    bl,9
  2577.         ja    asc_error
  2578.         mov    dx,10            ;DX holds base multiplier
  2579.         mul    dx             ;Shift over current number
  2580.         jc    asc_overflow        ;If overflow, indicate error
  2581.         add    ax,bx            ;Add new digit to sum.
  2582.         jcxz    asc_exit        ;If end of file, exit.
  2583.         mov    bl,ds:[si]        ;Get next ASCII character
  2584.         inc    si            ;Point to next character
  2585.         dec    cx            ;Dec file size counter
  2586.         jmp    short asc_loop        ;Go back for more
  2587. asc_exit:
  2588.         clc                ;Clear error flag.
  2589. asc_exit1:
  2590.         pop    bx
  2591.         ret
  2592. asc_overflow:
  2593.         mov    di,offset errmsg12    ;Number too large message.
  2594. asc_error:
  2595.         mov    dx,di            ;Copy message pointer.
  2596.         stc                ;Set error flag.
  2597.         jmp    short asc_exit1
  2598. asc2bin        endp
  2599. ;-----------------------------------------------------------------------------
  2600. ; SCANLINE performs the same function as SCAN4CHAR but keeps track of the
  2601. ; carriage returns.
  2602. ; Entry:  SI - pointer to ASCII string
  2603. ;         BL - 0 = find next char, 1 = find next space
  2604. ;         CX - file length
  2605. ; Exit:   AL - first nonspace character
  2606. ;         CF - set if carriage return found
  2607. ;-----------------------------------------------------------------------------
  2608. scanline    proc    near
  2609.         call    scan4char        ;Find the next char.
  2610.         jnc    scanline_exit
  2611.         inc    cs:[file_linecount]    ;Point to next line.
  2612.         stc
  2613. scanline_exit:
  2614.         ret
  2615. scanline    endp
  2616.  
  2617. end_of_code    =    $
  2618. code        ends
  2619.  
  2620. end        main
  2621. ------------